From 6f5607d9abd3880842f5abc935239c0e357e7d67 Mon Sep 17 00:00:00 2001 From: ashthespy Date: Sat, 23 Jan 2021 22:21:42 +0000 Subject: [PATCH 01/75] [Core] Bump hyper to ~0.12 --- core/Cargo.toml | 4 ++-- core/src/apresolve.rs | 32 ++++++++++++++++---------------- core/src/proxytunnel.rs | 2 +- core/src/session.rs | 3 +-- 4 files changed, 20 insertions(+), 21 deletions(-) diff --git a/core/Cargo.toml b/core/Cargo.toml index 8511878c3..d2eec63ff 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -19,8 +19,8 @@ bytes = "0.4" error-chain = { version = "0.12", default_features = false } futures = "0.1" httparse = "1.3" -hyper = "0.11" -hyper-proxy = { version = "0.4", default_features = false } +hyper = "0.12" +hyper-proxy = { version = "0.5", default_features = false } lazy_static = "1.3" log = "0.4" num-bigint = "0.3" diff --git a/core/src/apresolve.rs b/core/src/apresolve.rs index 94d942440..bea233181 100644 --- a/core/src/apresolve.rs +++ b/core/src/apresolve.rs @@ -3,11 +3,10 @@ const APRESOLVE_ENDPOINT: &'static str = "http://apresolve.spotify.com/"; use futures::{Future, Stream}; use hyper::client::HttpConnector; -use hyper::{self, Client, Method, Request, Uri}; +use hyper::{self, Client, Request, Uri}; use hyper_proxy::{Intercept, Proxy, ProxyConnector}; use serde_json; use std::str::FromStr; -use tokio_core::reactor::Handle; use url::Url; error_chain! {} @@ -18,35 +17,37 @@ pub struct APResolveData { } fn apresolve( - handle: &Handle, proxy: &Option, ap_port: &Option, ) -> Box> { let url = Uri::from_str(APRESOLVE_ENDPOINT).expect("invalid AP resolve URL"); let use_proxy = proxy.is_some(); - let mut req = Request::new(Method::Get, url.clone()); + // let mut req = Request::new(url.clone()); + let mut req = Request::get(url.clone()) + .body(hyper::Body::from(vec![])) + .unwrap(); let response = match *proxy { Some(ref val) => { let proxy_url = Uri::from_str(val.as_str()).expect("invalid http proxy"); let proxy = Proxy::new(Intercept::All, proxy_url); - let connector = HttpConnector::new(4, handle); + let connector = HttpConnector::new(4); let proxy_connector = ProxyConnector::from_proxy_unsecured(connector, proxy); if let Some(headers) = proxy_connector.http_headers(&url) { - req.headers_mut().extend(headers.iter()); - req.set_proxy(true); + req.headers_mut().extend(headers.clone().into_iter()); + // req.set_proxy(true); } - let client = Client::configure().connector(proxy_connector).build(handle); + let client = Client::builder().build(proxy_connector); client.request(req) } _ => { - let client = Client::new(handle); + let client = Client::new(); client.request(req) } }; let body = response.and_then(|response| { - response.body().fold(Vec::new(), |mut acc, chunk| { + response.into_body().fold(Vec::new(), |mut acc, chunk| { acc.extend_from_slice(chunk.as_ref()); Ok::<_, hyper::Error>(acc) }) @@ -64,13 +65,13 @@ fn apresolve( let mut aps = data.ap_list.iter().filter(|ap| { if p.is_some() { Uri::from_str(ap).ok().map_or(false, |uri| { - uri.port().map_or(false, |port| port == p.unwrap()) + uri.port_u16().map_or(false, |port| port == p.unwrap()) }) } else if use_proxy { // It is unlikely that the proxy will accept CONNECT on anything other than 443. - Uri::from_str(ap) - .ok() - .map_or(false, |uri| uri.port().map_or(false, |port| port == 443)) + Uri::from_str(ap).ok().map_or(false, |uri| { + uri.port_u16().map_or(false, |port| port == 443) + }) } else { true } @@ -84,14 +85,13 @@ fn apresolve( } pub(crate) fn apresolve_or_fallback( - handle: &Handle, proxy: &Option, ap_port: &Option, ) -> Box> where E: 'static, { - let ap = apresolve(handle, proxy, ap_port).or_else(|e| { + let ap = apresolve(proxy, ap_port).or_else(|e| { warn!("Failed to resolve Access Point: {}", e.description()); warn!("Using fallback \"{}\"", AP_FALLBACK); Ok(AP_FALLBACK.into()) diff --git a/core/src/proxytunnel.rs b/core/src/proxytunnel.rs index b13638469..e8fb13735 100644 --- a/core/src/proxytunnel.rs +++ b/core/src/proxytunnel.rs @@ -102,7 +102,7 @@ fn proxy_connect(connection: T, connect_url: &str) -> WriteAll, handle: Handle, ) -> Box> { - let access_point = - apresolve_or_fallback::(&handle, &config.proxy, &config.ap_port); + let access_point = apresolve_or_fallback::(&config.proxy, &config.ap_port); let handle_ = handle.clone(); let proxy = config.proxy.clone(); From 931c8207fc29e28728a8f034a7b540724a12733a Mon Sep 17 00:00:00 2001 From: ashthespy Date: Sat, 23 Jan 2021 22:21:42 +0000 Subject: [PATCH 02/75] [Connect] Migrate to hyper ~v12 --- connect/Cargo.toml | 2 +- connect/src/discovery.rs | 60 +++++++++++++++++++++++----------------- 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/connect/Cargo.toml b/connect/Cargo.toml index 8235870ac..f21faef35 100644 --- a/connect/Cargo.toml +++ b/connect/Cargo.toml @@ -20,7 +20,7 @@ version = "0.1.3" [dependencies] base64 = "0.13" futures = "0.1" -hyper = "0.11" +hyper = "0.12" log = "0.4" num-bigint = "0.3" protobuf = "~2.14.0" diff --git a/connect/src/discovery.rs b/connect/src/discovery.rs index 9779e6f86..e3bc22723 100644 --- a/connect/src/discovery.rs +++ b/connect/src/discovery.rs @@ -5,8 +5,10 @@ use base64; use futures::sync::mpsc; use futures::{Future, Poll, Stream}; use hmac::{Hmac, Mac}; -use hyper::server::{Http, Request, Response, Service}; -use hyper::{self, Get, Post, StatusCode}; + +use hyper::{ + self, server::conn::Http, service::Service, Body, Method, Request, Response, StatusCode, +}; use sha1::{Digest, Sha1}; #[cfg(feature = "with-dns-sd")] @@ -67,7 +69,7 @@ impl Discovery { fn handle_get_info( &self, _params: &BTreeMap, - ) -> ::futures::Finished { + ) -> ::futures::Finished, hyper::Error> { let public_key = self.0.public_key.to_bytes_be(); let public_key = base64::encode(&public_key); @@ -88,13 +90,13 @@ impl Discovery { }); let body = result.to_string(); - ::futures::finished(Response::new().with_body(body)) + ::futures::finished(Response::new(Body::from(body))) } fn handle_add_user( &self, params: &BTreeMap, - ) -> ::futures::Finished { + ) -> ::futures::Finished, hyper::Error> { let username = params.get("userName").unwrap(); let encrypted_blob = params.get("blob").unwrap(); let client_key = params.get("clientKey").unwrap(); @@ -136,7 +138,7 @@ impl Discovery { }); let body = result.to_string(); - return ::futures::finished(Response::new().with_body(body)); + return ::futures::finished(Response::new(Body::from(body))); } let decrypted = { @@ -161,30 +163,33 @@ impl Discovery { }); let body = result.to_string(); - ::futures::finished(Response::new().with_body(body)) + return ::futures::finished(Response::new(Body::from(body))); } - fn not_found(&self) -> ::futures::Finished { - ::futures::finished(Response::new().with_status(StatusCode::NotFound)) + fn not_found(&self) -> ::futures::Finished, hyper::Error> { + let mut res = Response::default(); + *res.status_mut() = StatusCode::NOT_FOUND; + ::futures::finished(res) } } impl Service for Discovery { - type Request = Request; - type Response = Response; + type ReqBody = Body; + type ResBody = Body; type Error = hyper::Error; - type Future = Box>; - fn call(&self, request: Request) -> Self::Future { + type Future = Box, Error = hyper::Error> + Send>; + fn call(&mut self, request: Request<(Self::ReqBody)>) -> Self::Future { let mut params = BTreeMap::new(); - let (method, uri, _, _, body) = request.deconstruct(); - if let Some(query) = uri.query() { + let (parts, body) = request.into_parts(); + + if let Some(query) = parts.uri.query() { params.extend(url::form_urlencoded::parse(query.as_bytes()).into_owned()); } - if method != Get { - debug!("{:?} {:?} {:?}", method, uri.path(), params); + if parts.method != Method::GET { + debug!("{:?} {:?} {:?}", parts.method, parts.uri.path(), params); } let this = self.clone(); @@ -198,9 +203,9 @@ impl Service for Discovery { params }) .and_then(move |params| { - match (method, params.get("action").map(AsRef::as_ref)) { - (Get, Some("getInfo")) => this.handle_get_info(¶ms), - (Post, Some("addUser")) => this.handle_add_user(¶ms), + match (parts.method, params.get("action").map(AsRef::as_ref)) { + (Method::GET, Some("getInfo")) => this.handle_get_info(¶ms), + (Method::POST, Some("addUser")) => this.handle_add_user(¶ms), _ => this.not_found(), } }), @@ -232,7 +237,7 @@ pub fn discovery( let http = Http::new(); http.serve_addr_handle( &format!("0.0.0.0:{}", port).parse().unwrap(), - &handle, + handle.new_tokio_handle(), move || Ok(discovery.clone()), ) .unwrap() @@ -244,10 +249,15 @@ pub fn discovery( let server_future = { let handle = handle.clone(); serve - .for_each(move |connection| { - handle.spawn(connection.then(|_| Ok(()))); - Ok(()) - }) + .for_each( + move |connecting: hyper::server::conn::Connecting< + hyper::server::conn::AddrStream, + futures::Failed<_, hyper::Error>, + >| { + handle.spawn(connecting.then(|_| Ok(()))); + Ok(()) + }, + ) .then(|_| Ok(())) }; handle.spawn(server_future); From 962d7af24df7bc2df24bacc7bd1068e402d9e0d2 Mon Sep 17 00:00:00 2001 From: ashthespy Date: Sat, 23 Jan 2021 22:21:42 +0000 Subject: [PATCH 03/75] Clean up hyper from binary --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 6405ca89b..89c4b4690 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,6 @@ base64 = "0.13" env_logger = {version = "0.8", default-features = false, features = ["termcolor","humantime","atty"]} futures = "0.1" getopts = "0.2" -hyper = "0.11" log = "0.4" num-bigint = "0.3" protobuf = "~2.14.0" From 9bbf8c3b26cef284eea5e193ce5755c4897b9d73 Mon Sep 17 00:00:00 2001 From: ashthespy Date: Sat, 23 Jan 2021 22:21:42 +0000 Subject: [PATCH 04/75] WIP tokio-core -> tokio migration --- audio/src/fetch.rs | 12 ++++++------ core/Cargo.toml | 2 +- core/src/connection/mod.rs | 6 ++---- core/src/lib.rs | 2 +- core/src/session.rs | 33 +++++++++++++++------------------ rustfmt.toml | 1 + src/main.rs | 33 ++++++++++++++------------------- 7 files changed, 40 insertions(+), 49 deletions(-) diff --git a/audio/src/fetch.rs b/audio/src/fetch.rs index c47cb4d3b..2214cdef8 100644 --- a/audio/src/fetch.rs +++ b/audio/src/fetch.rs @@ -328,7 +328,7 @@ impl AudioFileOpenStreaming { stream_loader_command_rx, complete_tx, ); - self.session.spawn(move |_| fetcher); + self.session.spawn(fetcher); AudioFileStreaming { read_file: read_file, @@ -425,7 +425,7 @@ impl AudioFile { }; let session_ = session.clone(); - session.spawn(move |_| { + session.spawn( complete_rx .map(move |mut file| { if let Some(cache) = session_.cache() { @@ -435,8 +435,8 @@ impl AudioFile { debug!("File {} complete", file_id); } }) - .or_else(|oneshot::Canceled| Ok(())) - }); + .or_else(|oneshot::Canceled| Ok(())), + ); return AudioFileOpen::Streaming(open); } @@ -671,7 +671,7 @@ impl AudioFileFetch { initial_request_sent_time, ); - session.spawn(move |_| initial_data_receiver); + session.spawn(initial_data_receiver); AudioFileFetch { session: session, @@ -746,7 +746,7 @@ impl AudioFileFetch { Instant::now(), ); - self.session.spawn(move |_| receiver); + self.session.spawn(receiver); } } diff --git a/core/Cargo.toml b/core/Cargo.toml index d2eec63ff..65ba04776 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -33,7 +33,7 @@ serde_derive = "1.0" serde_json = "1.0" shannon = "0.2.0" tokio-codec = "0.1" -tokio-core = "0.1" +tokio = "0.1" tokio-io = "0.1" url = "1.7" uuid = { version = "0.8", features = ["v4"] } diff --git a/core/src/connection/mod.rs b/core/src/connection/mod.rs index 72497795e..c0e95f527 100644 --- a/core/src/connection/mod.rs +++ b/core/src/connection/mod.rs @@ -8,9 +8,8 @@ use futures::{Future, Sink, Stream}; use protobuf::{self, Message}; use std::io; use std::net::ToSocketAddrs; +use tokio::net::TcpStream; use tokio_codec::Framed; -use tokio_core::net::TcpStream; -use tokio_core::reactor::Handle; use url::Url; use crate::authentication::Credentials; @@ -22,7 +21,6 @@ pub type Transport = Framed; pub fn connect( addr: String, - handle: &Handle, proxy: &Option, ) -> Box> { let (addr, connect_url) = match *proxy { @@ -51,7 +49,7 @@ pub fn connect( } }; - let socket = TcpStream::connect(&addr, handle); + let socket = TcpStream::connect(&addr); if let Some(connect_url) = connect_url { let connection = socket .and_then(move |socket| proxytunnel::connect(socket, &connect_url).and_then(handshake)); diff --git a/core/src/lib.rs b/core/src/lib.rs index c65878c2a..278478c1d 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -29,8 +29,8 @@ extern crate serde; extern crate serde_json; extern crate sha1; extern crate shannon; +extern crate tokio; extern crate tokio_codec; -extern crate tokio_core; extern crate tokio_io; extern crate url; extern crate uuid; diff --git a/core/src/session.rs b/core/src/session.rs index f1a24c1fa..4db2f1dc0 100644 --- a/core/src/session.rs +++ b/core/src/session.rs @@ -7,7 +7,8 @@ use byteorder::{BigEndian, ByteOrder}; use bytes::Bytes; use futures::sync::mpsc; use futures::{Async, Future, IntoFuture, Poll, Stream}; -use tokio_core::reactor::{Handle, Remote}; +use tokio::runtime::current_thread; +// use tokio::runtime::current_thread::Handle; use crate::apresolve::apresolve_or_fallback; use crate::audio_key::AudioKeyManager; @@ -37,8 +38,7 @@ struct SessionInternal { mercury: Lazy, cache: Option>, - handle: Remote, - + // handle: Handle, session_id: usize, } @@ -52,15 +52,14 @@ impl Session { config: SessionConfig, credentials: Credentials, cache: Option, - handle: Handle, + // handle: Handle, ) -> Box> { let access_point = apresolve_or_fallback::(&config.proxy, &config.ap_port); - let handle_ = handle.clone(); let proxy = config.proxy.clone(); let connection = access_point.and_then(move |addr| { info!("Connecting to AP \"{}\"", addr); - connection::connect(addr, &handle_, &proxy) + connection::connect(addr, &proxy) }); let device_id = config.device_id.clone(); @@ -75,15 +74,16 @@ impl Session { } let (session, task) = Session::create( - &handle, + // &handle, transport, config, cache, reusable_credentials.username.clone(), ); - handle.spawn(task.map_err(|e| { - error!("{:?}", e); + current_thread::spawn(task.map_err(|e| { + error!("SessionError: {}", e.to_string()); + std::process::exit(0); })); session @@ -93,7 +93,7 @@ impl Session { } fn create( - handle: &Handle, + // handle: &Handle, transport: connection::Transport, config: SessionConfig, cache: Option, @@ -123,8 +123,7 @@ impl Session { channel: Lazy::new(), mercury: Lazy::new(), - handle: handle.remote().clone(), - + // handle: handle.clone(), session_id: session_id, })); @@ -159,13 +158,11 @@ impl Session { self.0.data.read().unwrap().time_delta } - pub fn spawn(&self, f: F) + pub fn spawn(&self, f: F) where - F: FnOnce(&Handle) -> R + Send + 'static, - R: IntoFuture, - R::Future: 'static, + F: Future + 'static, { - self.0.handle.spawn(f) + current_thread::spawn(f); } fn debug_info(&self) { @@ -203,7 +200,7 @@ impl Session { 0x9 | 0xa => self.channel().dispatch(cmd, data), 0xd | 0xe => self.audio_key().dispatch(cmd, data), 0xb2..=0xb6 => self.mercury().dispatch(cmd, data), - _ => (), + _ => trace!("Unknown dispatch cmd :{:?} {:?}", cmd, data), } } diff --git a/rustfmt.toml b/rustfmt.toml index 25c1fc1ec..aefd6aa83 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,3 +1,4 @@ # max_width = 105 reorder_imports = true reorder_modules = true +edition = "2018" diff --git a/src/main.rs b/src/main.rs index 4f80657e2..8cc069033 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,7 +9,7 @@ use std::path::PathBuf; use std::process::exit; use std::str::FromStr; use std::time::Instant; -use tokio_core::reactor::{Core, Handle}; +// use tokio_core::reactor::{Core, Handle}; use tokio_io::IoStream; use url::Url; @@ -26,6 +26,8 @@ use librespot::playback::config::{Bitrate, PlayerConfig}; use librespot::playback::mixer::{self, Mixer, MixerConfig}; use librespot::playback::player::{Player, PlayerEvent}; +use tokio::runtime::current_thread; + mod player_event_handler; use crate::player_event_handler::{emit_sink_event, run_program_on_events}; @@ -399,8 +401,6 @@ struct Main { device: Option, mixer: fn(Option) -> Box, mixer_config: MixerConfig, - handle: Handle, - discovery: Option, signal: IoStream<()>, @@ -418,9 +418,8 @@ struct Main { } impl Main { - fn new(handle: Handle, setup: Setup) -> Main { + fn new(setup: Setup) -> Main { let mut task = Main { - handle: handle.clone(), cache: setup.cache, session_config: setup.session_config, player_config: setup.player_config, @@ -444,13 +443,12 @@ impl Main { emit_sink_events: setup.emit_sink_events, }; - if setup.enable_discovery { - let config = task.connect_config.clone(); - let device_id = task.session_config.device_id.clone(); - - task.discovery = - Some(discovery(&handle, config, device_id, setup.zeroconf_port).unwrap()); - } + // if setup.enable_discovery { + // let config = task.connect_config.clone(); + // let device_id = task.session_config.device_id.clone(); + // + // task.discovery = Some(discovery(config, device_id, setup.zeroconf_port).unwrap()); + // } if let Some(credentials) = setup.credentials { task.credentials(credentials); @@ -462,15 +460,14 @@ impl Main { fn credentials(&mut self, credentials: Credentials) { self.last_credentials = Some(credentials.clone()); let config = self.session_config.clone(); - let handle = self.handle.clone(); - let connection = Session::connect(config, credentials, self.cache.clone(), handle); + let connection = Session::connect(config, credentials, self.cache.clone()); self.connect = connection; self.spirc = None; let task = mem::replace(&mut self.spirc_task, None); if let Some(task) = task { - self.handle.spawn(task); + current_thread::spawn(Box::new(task)); } } } @@ -594,7 +591,7 @@ impl Future for Main { }) .map_err(|e| error!("failed to wait on child process: {}", e)); - self.handle.spawn(child); + current_thread::spawn(child); } } } @@ -611,10 +608,8 @@ fn main() { if env::var("RUST_BACKTRACE").is_err() { env::set_var("RUST_BACKTRACE", "full") } - let mut core = Core::new().unwrap(); - let handle = core.handle(); let args: Vec = std::env::args().collect(); - core.run(Main::new(handle, setup(&args))).unwrap() + current_thread::block_on_all(Main::new(setup(&args))).unwrap() } From 53b4ab05ba9f1627d568c0193cc246fb9cae3fca Mon Sep 17 00:00:00 2001 From: ashthespy Date: Sat, 23 Jan 2021 22:21:42 +0000 Subject: [PATCH 05/75] Migrate to `tokio` 0.1 --- Cargo.toml | 3 ++- core/src/session.rs | 46 +++++++++++++++++++++++++++++++++++---------- src/main.rs | 20 ++++++++++++++------ 3 files changed, 52 insertions(+), 17 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 89c4b4690..f56649d08 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,8 @@ num-bigint = "0.3" protobuf = "~2.14.0" rand = "0.7" rpassword = "5.0" -tokio-core = "0.1" +rpassword = "3.0" +tokio = "0.1" tokio-io = "0.1" tokio-process = "0.2" tokio-signal = "0.2" diff --git a/core/src/session.rs b/core/src/session.rs index 4db2f1dc0..1f8313f3e 100644 --- a/core/src/session.rs +++ b/core/src/session.rs @@ -1,14 +1,13 @@ use std::io; use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::{Arc, RwLock, Weak}; +use std::sync::{Arc, Mutex, RwLock, Weak}; use std::time::{SystemTime, UNIX_EPOCH}; use byteorder::{BigEndian, ByteOrder}; use bytes::Bytes; use futures::sync::mpsc; use futures::{Async, Future, IntoFuture, Poll, Stream}; -use tokio::runtime::current_thread; -// use tokio::runtime::current_thread::Handle; +use tokio::runtime::{current_thread, current_thread::Handle}; use crate::apresolve::apresolve_or_fallback; use crate::audio_key::AudioKeyManager; @@ -38,7 +37,7 @@ struct SessionInternal { mercury: Lazy, cache: Option>, - // handle: Handle, + handle: Mutex, session_id: usize, } @@ -52,7 +51,7 @@ impl Session { config: SessionConfig, credentials: Credentials, cache: Option, - // handle: Handle, + handle: Handle, ) -> Box> { let access_point = apresolve_or_fallback::(&config.proxy, &config.ap_port); @@ -74,7 +73,7 @@ impl Session { } let (session, task) = Session::create( - // &handle, + &handle, transport, config, cache, @@ -93,7 +92,7 @@ impl Session { } fn create( - // handle: &Handle, + handle: &Handle, transport: connection::Transport, config: SessionConfig, cache: Option, @@ -123,7 +122,7 @@ impl Session { channel: Lazy::new(), mercury: Lazy::new(), - // handle: handle.clone(), + handle: Mutex::new(handle.clone()), session_id: session_id, })); @@ -158,13 +157,40 @@ impl Session { self.0.data.read().unwrap().time_delta } + // Spawn a future directly pub fn spawn(&self, f: F) where - F: Future + 'static, + F: Future + Send + 'static, { - current_thread::spawn(f); + let handle = self.0.handle.lock().unwrap(); + let spawn_res = handle.spawn(f); + match spawn_res { + Ok(_) => (), + Err(e) => error!("Session SpawnErr {:?}", e), + } } + // pub fn spawn(&self, f: F) + // where + // F: FnOnce() -> R + Send + 'static, + // R: Future + Send + 'static, + // { + // // This fails when called from a different thread + // // current_thread::spawn(future::lazy(|| f())); + // + // // These fail when the Future doesn't implement Send + // let handle = self.0.handle.lock().unwrap(); + // let spawn_res = handle.spawn(lazy(|| f())); + // + // // let mut te = current_thread::TaskExecutor::current(); + // // let spawn_res = te.spawn_local(Box::new(future::lazy(|| f()))); + // + // match spawn_res { + // Ok(_) => (), + // Err(e) => error!("Session SpawnErr {:?}", e), + // } + // } + fn debug_info(&self) { debug!( "Session[{}] strong={} weak={}", diff --git a/src/main.rs b/src/main.rs index 8cc069033..6673310b6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,7 +9,6 @@ use std::path::PathBuf; use std::process::exit; use std::str::FromStr; use std::time::Instant; -// use tokio_core::reactor::{Core, Handle}; use tokio_io::IoStream; use url::Url; @@ -26,7 +25,10 @@ use librespot::playback::config::{Bitrate, PlayerConfig}; use librespot::playback::mixer::{self, Mixer, MixerConfig}; use librespot::playback::player::{Player, PlayerEvent}; -use tokio::runtime::current_thread; +use tokio::runtime::{ + current_thread, + current_thread::{Handle, Runtime}, +}; mod player_event_handler; use crate::player_event_handler::{emit_sink_event, run_program_on_events}; @@ -401,6 +403,7 @@ struct Main { device: Option, mixer: fn(Option) -> Box, mixer_config: MixerConfig, + handle: Handle, discovery: Option, signal: IoStream<()>, @@ -418,8 +421,9 @@ struct Main { } impl Main { - fn new(setup: Setup) -> Main { + fn new(handle: Handle, setup: Setup) -> Main { let mut task = Main { + handle: handle, cache: setup.cache, session_config: setup.session_config, player_config: setup.player_config, @@ -460,8 +464,8 @@ impl Main { fn credentials(&mut self, credentials: Credentials) { self.last_credentials = Some(credentials.clone()); let config = self.session_config.clone(); - - let connection = Session::connect(config, credentials, self.cache.clone()); + let handle = self.handle.clone(); + let connection = Session::connect(config, credentials, self.cache.clone(), handle); self.connect = connection; self.spirc = None; @@ -611,5 +615,9 @@ fn main() { let args: Vec = std::env::args().collect(); - current_thread::block_on_all(Main::new(setup(&args))).unwrap() + let mut runtime = Runtime::new().unwrap(); + let handle = runtime.handle(); + runtime.block_on(Main::new(handle, setup(&args))).unwrap(); + runtime.run().unwrap(); + // current_thread::block_on_all(Main::new(setup(&args))).unwrap() } From c69ccf77e99c6d19ca10818d4841de12e6329c33 Mon Sep 17 00:00:00 2001 From: ashthespy Date: Sat, 23 Jan 2021 22:21:42 +0000 Subject: [PATCH 06/75] [Connect] Migrate to `tokio` 0.1 --- connect/Cargo.toml | 3 ++- connect/src/discovery.rs | 14 ++++++-------- connect/src/lib.rs | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/connect/Cargo.toml b/connect/Cargo.toml index f21faef35..b5cd4fdb1 100644 --- a/connect/Cargo.toml +++ b/connect/Cargo.toml @@ -28,7 +28,7 @@ rand = "0.7" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" -tokio-core = "0.1" +tokio = "0.1" url = "1.7" sha-1 = "0.8" hmac = "0.7" @@ -38,6 +38,7 @@ block-modes = "0.3" dns-sd = { version = "0.1.3", optional = true } libmdns = { version = "0.2.7", optional = true } + [features] default = ["libmdns"] with-dns-sd = ["dns-sd"] diff --git a/connect/src/discovery.rs b/connect/src/discovery.rs index e3bc22723..6c542e6b9 100644 --- a/connect/src/discovery.rs +++ b/connect/src/discovery.rs @@ -22,7 +22,7 @@ use rand; use std::collections::BTreeMap; use std::io; use std::sync::Arc; -use tokio_core::reactor::Handle; +use tokio::runtime::current_thread::Handle; use url; use librespot_core::authentication::Credentials; @@ -235,11 +235,9 @@ pub fn discovery( let serve = { let http = Http::new(); - http.serve_addr_handle( - &format!("0.0.0.0:{}", port).parse().unwrap(), - handle.new_tokio_handle(), - move || Ok(discovery.clone()), - ) + http.serve_addr(&format!("0.0.0.0:{}", port).parse().unwrap(), move || { + Ok(discovery.clone()) + }) .unwrap() }; @@ -254,13 +252,13 @@ pub fn discovery( hyper::server::conn::AddrStream, futures::Failed<_, hyper::Error>, >| { - handle.spawn(connecting.then(|_| Ok(()))); + handle.spawn(connecting.flatten().then(|_| Ok(()))).unwrap(); Ok(()) }, ) .then(|_| Ok(())) }; - handle.spawn(server_future); + handle.spawn(server_future).unwrap(); #[cfg(feature = "with-dns-sd")] let svc = DNSService::register( diff --git a/connect/src/lib.rs b/connect/src/lib.rs index 118c85dfa..47777606e 100644 --- a/connect/src/lib.rs +++ b/connect/src/lib.rs @@ -12,7 +12,7 @@ extern crate hyper; extern crate num_bigint; extern crate protobuf; extern crate rand; -extern crate tokio_core; +extern crate tokio; extern crate url; extern crate aes_ctr; From 47a1575c00ee1b0abee98599e3e2d478638e18ca Mon Sep 17 00:00:00 2001 From: ashthespy Date: Sat, 23 Jan 2021 22:21:42 +0000 Subject: [PATCH 07/75] WIP Futures Fix apresolve WIP session [Core] More migration Playing with `ReadExact` and `WriteAll` Add some simple checks Take little steps --- audio/Cargo.toml | 3 +- audio/src/fetch.rs | 122 ++++++++++++++------------- core/Cargo.toml | 13 +-- core/src/apresolve.rs | 72 ++++++---------- core/src/audio_key.rs | 19 +++-- core/src/channel.rs | 63 +++++++------- core/src/connection/codec.rs | 8 +- core/src/connection/handshake.rs | 86 ++++++++++--------- core/src/connection/mod.rs | 136 +++++++++++++++---------------- core/src/keymaster.rs | 12 +-- core/src/lib.rs | 12 +-- core/src/mercury/mod.rs | 28 ++++--- core/src/mercury/sender.rs | 24 +++--- core/src/proxytunnel.rs | 60 ++++++++------ core/src/session.rs | 133 +++++++++++++++++------------- core/tests/connect.rs | 23 ++++++ 16 files changed, 436 insertions(+), 378 deletions(-) create mode 100644 core/tests/connect.rs diff --git a/audio/Cargo.toml b/audio/Cargo.toml index cde907c1a..5f6a94260 100644 --- a/audio/Cargo.toml +++ b/audio/Cargo.toml @@ -14,7 +14,8 @@ version = "0.1.3" bit-set = "0.5" byteorder = "1.3" bytes = "0.4" -futures = "0.1" +futures = "0.3" +tokio = { version = "0.2", features = ["full"] } # Temp "rt-core", "sync" lewton = "0.9" log = "0.4" num-bigint = "0.3" diff --git a/audio/src/fetch.rs b/audio/src/fetch.rs index 2214cdef8..5ed4ccd15 100644 --- a/audio/src/fetch.rs +++ b/audio/src/fetch.rs @@ -1,9 +1,6 @@ use crate::range_set::{Range, RangeSet}; use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; use bytes::Bytes; -use futures::sync::{mpsc, oneshot}; -use futures::Stream; -use futures::{Async, Future, Poll}; use std::cmp::{max, min}; use std::fs; use std::io::{self, Read, Seek, SeekFrom, Write}; @@ -11,13 +8,23 @@ use std::sync::{Arc, Condvar, Mutex}; use std::time::{Duration, Instant}; use tempfile::NamedTempFile; -use futures::sync::mpsc::unbounded; use librespot_core::channel::{Channel, ChannelData, ChannelError, ChannelHeaders}; use librespot_core::session::Session; use librespot_core::spotify_id::FileId; use std::sync::atomic; use std::sync::atomic::AtomicUsize; +use futures::{ + channel::{mpsc, mpsc::unbounded, oneshot}, + ready, Future, Stream, +}; +use std::{ + pin::Pin, + task::{Context, Poll}, +}; + +use tokio::task; + const MINIMUM_DOWNLOAD_SIZE: usize = 1024 * 16; // The minimum size of a block that is requested from the Spotify servers in one request. // This is the block size that is typically requested while doing a seek() on a file. @@ -329,6 +336,7 @@ impl AudioFileOpenStreaming { complete_tx, ); self.session.spawn(fetcher); + // tokio::spawn(move |_| fetcher); AudioFileStreaming { read_file: read_file, @@ -343,36 +351,37 @@ impl AudioFileOpenStreaming { } impl Future for AudioFileOpen { - type Item = AudioFile; - type Error = ChannelError; + type Output = Result; - fn poll(&mut self) -> Poll { + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { match *self { AudioFileOpen::Streaming(ref mut open) => { - let file = try_ready!(open.poll()); - Ok(Async::Ready(AudioFile::Streaming(file))) + let file = ready!(open.poll()); + Poll::Ready(Ok(AudioFile::Streaming(file))) } AudioFileOpen::Cached(ref mut file) => { let file = file.take().unwrap(); - Ok(Async::Ready(AudioFile::Cached(file))) + Poll::Ready(Ok(AudioFile::Cached(file))) } } } } impl Future for AudioFileOpenStreaming { - type Item = AudioFileStreaming; - type Error = ChannelError; + type Output = Result; - fn poll(&mut self) -> Poll { + fn poll( + self: Pin<&mut Self>, + cx: &mut Context, + ) -> Poll> { loop { - let (id, data) = try_ready!(self.headers.poll()).unwrap(); + let (id, data) = ready!(self.headers.poll()).unwrap(); if id == 0x3 { let size = BigEndian::read_u32(&data) as usize * 4; let file = self.finish(size); - return Ok(Async::Ready(file)); + return Poll::Ready(Ok(file)); } } } @@ -563,13 +572,12 @@ impl AudioFileFetchDataReceiver { } impl Future for AudioFileFetchDataReceiver { - type Item = (); - type Error = (); + type Output = (); - fn poll(&mut self) -> Poll<(), ()> { + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<()> { loop { match self.data_rx.poll() { - Ok(Async::Ready(Some(data))) => { + Poll::Ready(Some(data)) => { if self.measure_ping_time { if let Some(request_sent_time) = self.request_sent_time { let duration = Instant::now() - request_sent_time; @@ -603,26 +611,24 @@ impl Future for AudioFileFetchDataReceiver { } if self.request_length == 0 { self.finish(); - return Ok(Async::Ready(())); + return Poll::Ready(()); } } - Ok(Async::Ready(None)) => { + Poll::Ready(None) => { if self.request_length > 0 { warn!("Data receiver for range {} (+{}) received less data from server than requested.", self.initial_data_offset, self.initial_request_length); } self.finish(); - return Ok(Async::Ready(())); - } - Ok(Async::NotReady) => { - return Ok(Async::NotReady); + return Poll::Ready(()); } + Poll::Pending => return Poll::Pending, Err(ChannelError) => { warn!( "Error from channel for data receiver for range {} (+{}).", self.initial_data_offset, self.initial_request_length ); self.finish(); - return Ok(Async::Ready(())); + return Poll::Ready(()); } } } @@ -672,6 +678,7 @@ impl AudioFileFetch { ); session.spawn(initial_data_receiver); + // tokio::spawn(move |_| initial_data_receiver); AudioFileFetch { session: session, @@ -747,6 +754,7 @@ impl AudioFileFetch { ); self.session.spawn(receiver); + // tokio::spawn(move |_| receiver); } } @@ -794,13 +802,11 @@ impl AudioFileFetch { } } - fn poll_file_data_rx(&mut self) -> Poll<(), ()> { + fn poll_file_data_rx(&mut self) -> Poll<()> { loop { match self.file_data_rx.poll() { - Ok(Async::Ready(None)) => { - return Ok(Async::Ready(())); - } - Ok(Async::Ready(Some(ReceivedData::ResponseTimeMs(response_time_ms)))) => { + Poll::Ready(None) => return Poll::Ready(()), + Poll::Ready(Some(ReceivedData::ResponseTimeMs(response_time_ms))) => { trace!("Ping time estimated as: {} ms.", response_time_ms); // record the response time @@ -832,7 +838,7 @@ impl AudioFileFetch { .ping_time_ms .store(ping_time_ms, atomic::Ordering::Relaxed); } - Ok(Async::Ready(Some(ReceivedData::Data(data)))) => { + Poll::Ready(Some(ReceivedData::Data(data))) => { self.output .as_mut() .unwrap() @@ -864,39 +870,34 @@ impl AudioFileFetch { if full { self.finish(); - return Ok(Async::Ready(())); + return Poll::Ready(()); } } - Ok(Async::NotReady) => { - return Ok(Async::NotReady); - } - Err(()) => unreachable!(), + Poll::Pending => return Poll::Pending, + // Err(()) => unreachable!(), } } } - fn poll_stream_loader_command_rx(&mut self) -> Poll<(), ()> { + fn poll_stream_loader_command_rx(&mut self) -> Poll<()> { loop { match self.stream_loader_command_rx.poll() { - Ok(Async::Ready(None)) => { - return Ok(Async::Ready(())); - } - Ok(Async::Ready(Some(StreamLoaderCommand::Fetch(request)))) => { + Poll::Ready(None) => return Poll::Ready(()), + + Poll::Ready(Some(StreamLoaderCommand::Fetch(request))) => { self.download_range(request.start, request.length); } - Ok(Async::Ready(Some(StreamLoaderCommand::RandomAccessMode()))) => { + Poll::Ready(Some(StreamLoaderCommand::RandomAccessMode())) => { *(self.shared.download_strategy.lock().unwrap()) = DownloadStrategy::RandomAccess(); } - Ok(Async::Ready(Some(StreamLoaderCommand::StreamMode()))) => { + Poll::Ready(Some(StreamLoaderCommand::StreamMode())) => { *(self.shared.download_strategy.lock().unwrap()) = DownloadStrategy::Streaming(); } - Ok(Async::Ready(Some(StreamLoaderCommand::Close()))) => { - return Ok(Async::Ready(())); - } - Ok(Async::NotReady) => return Ok(Async::NotReady), - Err(()) => unreachable!(), + Poll::Ready(Some(StreamLoaderCommand::Close())) => return Poll::Ready(()), + Poll::Pending => return Poll::Pending, + // Err(()) => unreachable!(), } } } @@ -911,24 +912,19 @@ impl AudioFileFetch { } impl Future for AudioFileFetch { - type Item = (); - type Error = (); + type Output = (); - fn poll(&mut self) -> Poll<(), ()> { + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<()> { match self.poll_stream_loader_command_rx() { - Ok(Async::NotReady) => (), - Ok(Async::Ready(_)) => { - return Ok(Async::Ready(())); - } - Err(()) => unreachable!(), + Poll::Pending => (), + Poll::Ready(_) => return Poll::Ready(()), + // Err(()) => unreachable!(), } match self.poll_file_data_rx() { - Ok(Async::NotReady) => (), - Ok(Async::Ready(_)) => { - return Ok(Async::Ready(())); - } - Err(()) => unreachable!(), + Poll::Pending => (), + Poll::Ready(_) => return Poll::Ready(()), + // Err(()) => unreachable!(), } if let DownloadStrategy::Streaming() = self.get_download_strategy() { @@ -969,7 +965,7 @@ impl Future for AudioFileFetch { } } - return Ok(Async::NotReady); + return Poll::Pending; } } diff --git a/core/Cargo.toml b/core/Cargo.toml index 65ba04776..8c9475a61 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -17,10 +17,10 @@ base64 = "0.13" byteorder = "1.3" bytes = "0.4" error-chain = { version = "0.12", default_features = false } -futures = "0.1" +futures = {version = "0.3",features =["unstable","bilock"]} httparse = "1.3" -hyper = "0.12" -hyper-proxy = { version = "0.5", default_features = false } +hyper = "0.13" +hyper-proxy = { version = "0.6", default_features = false } lazy_static = "1.3" log = "0.4" num-bigint = "0.3" @@ -32,9 +32,10 @@ serde = "1.0" serde_derive = "1.0" serde_json = "1.0" shannon = "0.2.0" -tokio-codec = "0.1" -tokio = "0.1" -tokio-io = "0.1" +tokio = {version = "0.2", features = ["full","io-util","tcp"]} # io-util +tokio-util = {version = "0.3", features = ["compat","codec"]} +# tokio-codec = "0.1" +# tokio-io = "0.1" url = "1.7" uuid = { version = "0.8", features = ["v4"] } sha-1 = "0.8" diff --git a/core/src/apresolve.rs b/core/src/apresolve.rs index bea233181..cf3017885 100644 --- a/core/src/apresolve.rs +++ b/core/src/apresolve.rs @@ -1,41 +1,33 @@ const AP_FALLBACK: &'static str = "ap.spotify.com:443"; const APRESOLVE_ENDPOINT: &'static str = "http://apresolve.spotify.com/"; -use futures::{Future, Stream}; use hyper::client::HttpConnector; -use hyper::{self, Client, Request, Uri}; +use hyper::{self, Body, Client, Request, Uri}; use hyper_proxy::{Intercept, Proxy, ProxyConnector}; use serde_json; +use std::error; use std::str::FromStr; use url::Url; -error_chain! {} - #[derive(Clone, Debug, Serialize, Deserialize)] pub struct APResolveData { ap_list: Vec, } +type Result = std::result::Result>; -fn apresolve( - proxy: &Option, - ap_port: &Option, -) -> Box> { - let url = Uri::from_str(APRESOLVE_ENDPOINT).expect("invalid AP resolve URL"); +async fn apresolve(proxy: &Option, ap_port: &Option) -> Result { + let url = Uri::from_str(APRESOLVE_ENDPOINT)?; //.expect("invalid AP resolve URL"); let use_proxy = proxy.is_some(); - // let mut req = Request::new(url.clone()); - let mut req = Request::get(url.clone()) - .body(hyper::Body::from(vec![])) - .unwrap(); + let mut req = Request::get(&url).body(Body::empty())?; let response = match *proxy { Some(ref val) => { let proxy_url = Uri::from_str(val.as_str()).expect("invalid http proxy"); let proxy = Proxy::new(Intercept::All, proxy_url); - let connector = HttpConnector::new(4); + let connector = HttpConnector::new(); let proxy_connector = ProxyConnector::from_proxy_unsecured(connector, proxy); if let Some(headers) = proxy_connector.http_headers(&url) { req.headers_mut().extend(headers.clone().into_iter()); - // req.set_proxy(true); } let client = Client::builder().build(proxy_connector); client.request(req) @@ -44,29 +36,19 @@ fn apresolve( let client = Client::new(); client.request(req) } - }; - - let body = response.and_then(|response| { - response.into_body().fold(Vec::new(), |mut acc, chunk| { - acc.extend_from_slice(chunk.as_ref()); - Ok::<_, hyper::Error>(acc) - }) - }); - let body = body.then(|result| result.chain_err(|| "HTTP error")); - let body = - body.and_then(|body| String::from_utf8(body).chain_err(|| "invalid UTF8 in response")); + } + .await?; - let data = body - .and_then(|body| serde_json::from_str::(&body).chain_err(|| "invalid JSON")); + let body = hyper::body::to_bytes(response.into_body()).await?; + let body = String::from_utf8(body.to_vec())?; + let data = serde_json::from_str::(&body)?; - let p = ap_port.clone(); - - let ap = data.and_then(move |data| { + let ap = { let mut aps = data.ap_list.iter().filter(|ap| { - if p.is_some() { - Uri::from_str(ap).ok().map_or(false, |uri| { - uri.port_u16().map_or(false, |port| port == p.unwrap()) - }) + if let Some(p) = ap_port { + Uri::from_str(ap) + .ok() + .map_or(false, |uri| uri.port_u16().map_or(false, |port| &port == p)) } else if use_proxy { // It is unlikely that the proxy will accept CONNECT on anything other than 443. Uri::from_str(ap).ok().map_or(false, |uri| { @@ -79,23 +61,23 @@ fn apresolve( let ap = aps.next().ok_or("empty AP List")?; Ok(ap.clone()) - }); + }; - Box::new(ap) + ap } -pub(crate) fn apresolve_or_fallback( +pub(crate) async fn apresolve_or_fallback( proxy: &Option, ap_port: &Option, -) -> Box> -where - E: 'static, -{ - let ap = apresolve(proxy, ap_port).or_else(|e| { - warn!("Failed to resolve Access Point: {}", e.description()); +) -> Result { + // match apresolve.await { + // Ok(ap) + // } + let ap = apresolve(proxy, ap_port).await.or_else(|e| { + warn!("Failed to resolve Access Point: {:?}", e); warn!("Using fallback \"{}\"", AP_FALLBACK); Ok(AP_FALLBACK.into()) }); - Box::new(ap) + ap } diff --git a/core/src/audio_key.rs b/core/src/audio_key.rs index 1e5310c21..39eef721e 100644 --- a/core/src/audio_key.rs +++ b/core/src/audio_key.rs @@ -1,10 +1,14 @@ use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; use bytes::Bytes; -use futures::sync::oneshot; -use futures::{Async, Future, Poll}; use std::collections::HashMap; use std::io::Write; +use futures::{channel::oneshot, Future}; +use std::{ + pin::Pin, + task::{Context, Poll}, +}; + use crate::spotify_id::{FileId, SpotifyId}; use crate::util::SeqGenerator; @@ -73,14 +77,13 @@ impl AudioKeyManager { pub struct AudioKeyFuture(oneshot::Receiver>); impl Future for AudioKeyFuture { - type Item = T; - type Error = AudioKeyError; + type Output = Result; - fn poll(&mut self) -> Poll { + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { match self.0.poll() { - Ok(Async::Ready(Ok(value))) => Ok(Async::Ready(value)), - Ok(Async::Ready(Err(err))) => Err(err), - Ok(Async::NotReady) => Ok(Async::NotReady), + Poll::Ready(Ok(Ok(value))) => Poll::Ready(Ok(value)), + Poll::Ready(Ok(Err(err))) => Err(err), + Poll::Pending => Poll::Pending, Err(oneshot::Canceled) => Err(AudioKeyError), } } diff --git a/core/src/channel.rs b/core/src/channel.rs index b614fac49..f789bfe44 100644 --- a/core/src/channel.rs +++ b/core/src/channel.rs @@ -1,12 +1,16 @@ use byteorder::{BigEndian, ByteOrder}; use bytes::Bytes; -use futures::sync::{mpsc, BiLock}; -use futures::{Async, Poll, Stream}; use std::collections::HashMap; use std::time::Instant; use crate::util::SeqGenerator; +use futures::{channel::mpsc, lock::BiLock, Stream}; +use std::{ + pin::Pin, + task::{Context, Poll}, +}; + component! { ChannelManager : ChannelManagerInner { sequence: SeqGenerator = SeqGenerator::new(0), @@ -101,11 +105,11 @@ impl ChannelManager { } impl Channel { - fn recv_packet(&mut self) -> Poll { + fn recv_packet(&mut self) -> Poll> { let (cmd, packet) = match self.receiver.poll() { - Ok(Async::Ready(Some(t))) => t, - Ok(Async::Ready(None)) => return Err(ChannelError), // The channel has been closed. - Ok(Async::NotReady) => return Ok(Async::NotReady), + Poll::Ready(Ok(Some(t))) => t, + Poll::Ready(Ok(t)) => return Err(ChannelError), // The channel has been closed. + Poll::Pending => return Poll::Pending, Err(()) => unreachable!(), }; @@ -117,7 +121,7 @@ impl Channel { Err(ChannelError) } else { - Ok(Async::Ready(packet)) + Poll::Ready(Ok(packet)) } } @@ -129,16 +133,15 @@ impl Channel { } impl Stream for Channel { - type Item = ChannelEvent; - type Error = ChannelError; + type Item = Result, ChannelError>; - fn poll(&mut self) -> Poll, Self::Error> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { loop { match self.state.clone() { ChannelState::Closed => panic!("Polling already terminated channel"), ChannelState::Header(mut data) => { if data.len() == 0 { - data = try_ready!(self.recv_packet()); + data = ready!(self.recv_packet()); } let length = BigEndian::read_u16(data.split_to(2).as_ref()) as usize; @@ -152,19 +155,19 @@ impl Stream for Channel { self.state = ChannelState::Header(data); let event = ChannelEvent::Header(header_id, header_data); - return Ok(Async::Ready(Some(event))); + return Poll::Ready(Ok(Some(event))); } } ChannelState::Data => { - let data = try_ready!(self.recv_packet()); + let data = ready!(self.recv_packet()); if data.len() == 0 { self.receiver.close(); self.state = ChannelState::Closed; - return Ok(Async::Ready(None)); + return Poll::Ready(Ok(None)); } else { let event = ChannelEvent::Data(data); - return Ok(Async::Ready(Some(event))); + return Poll::Ready(Ok(Some(event))); } } } @@ -173,38 +176,36 @@ impl Stream for Channel { } impl Stream for ChannelData { - type Item = Bytes; - type Error = ChannelError; + type Item = Result, ChannelError>; - fn poll(&mut self) -> Poll, Self::Error> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { let mut channel = match self.0.poll_lock() { - Async::Ready(c) => c, - Async::NotReady => return Ok(Async::NotReady), + Poll::Ready(c) => c, + Poll::Pending => return Poll::Pending, }; loop { - match try_ready!(channel.poll()) { + match ready!(channel.poll()) { Some(ChannelEvent::Header(..)) => (), - Some(ChannelEvent::Data(data)) => return Ok(Async::Ready(Some(data))), - None => return Ok(Async::Ready(None)), + Some(ChannelEvent::Data(data)) => return Poll::Ready(Ok(Some(data))), + None => return Poll::Ready(Ok(None)), } } } } impl Stream for ChannelHeaders { - type Item = (u8, Vec); - type Error = ChannelError; + type Item = Result)>, ChannelError>; - fn poll(&mut self) -> Poll, Self::Error> { + fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { let mut channel = match self.0.poll_lock() { - Async::Ready(c) => c, - Async::NotReady => return Ok(Async::NotReady), + Poll::Ready(c) => c, + Poll::Pending => return Poll::Pending, }; - match try_ready!(channel.poll()) { - Some(ChannelEvent::Header(id, data)) => Ok(Async::Ready(Some((id, data)))), - Some(ChannelEvent::Data(..)) | None => Ok(Async::Ready(None)), + match ready!(channel.poll()) { + Some(ChannelEvent::Header(id, data)) => Poll::Ready(Ok(Some((id, data)))), + Some(ChannelEvent::Data(..)) | None => Poll::Ready(Ok(None)), } } } diff --git a/core/src/connection/codec.rs b/core/src/connection/codec.rs index fa4cd9d99..47e116308 100644 --- a/core/src/connection/codec.rs +++ b/core/src/connection/codec.rs @@ -2,7 +2,7 @@ use byteorder::{BigEndian, ByteOrder}; use bytes::{BufMut, Bytes, BytesMut}; use shannon::Shannon; use std::io; -use tokio_io::codec::{Decoder, Encoder}; +use tokio_util::codec::{Decoder, Encoder}; const HEADER_SIZE: usize = 3; const MAC_SIZE: usize = 4; @@ -35,11 +35,11 @@ impl APCodec { } } -impl Encoder for APCodec { - type Item = (u8, Vec); +type APCodecItem = (u8, Vec); +impl Encoder for APCodec { type Error = io::Error; - fn encode(&mut self, item: (u8, Vec), buf: &mut BytesMut) -> io::Result<()> { + fn encode(&mut self, item: APCodecItem, buf: &mut BytesMut) -> io::Result<()> { let (cmd, payload) = item; let offset = buf.len(); diff --git a/core/src/connection/handshake.rs b/core/src/connection/handshake.rs index 220ab6e83..512f61cd4 100644 --- a/core/src/connection/handshake.rs +++ b/core/src/connection/handshake.rs @@ -1,14 +1,13 @@ use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; -use futures::{Async, Future, Poll}; use hmac::{Hmac, Mac}; use protobuf::{self, Message}; use rand::thread_rng; use sha1::Sha1; use std::io::{self, Read}; use std::marker::PhantomData; -use tokio_codec::{Decoder, Framed}; -use tokio_io::io::{read_exact, write_all, ReadExact, Window, WriteAll}; -use tokio_io::{AsyncRead, AsyncWrite}; +// use tokio_codec::{Decoder, Framed}; +// use tokio_io::io::{read_exact, write_all, ReadExact, Window, WriteAll}; +// use tokio_io::{AsyncRead, AsyncWrite}; use super::codec::APCodec; use crate::diffie_hellman::DHLocalKeys; @@ -16,18 +15,30 @@ use crate::protocol; use crate::protocol::keyexchange::{APResponseMessage, ClientHello, ClientResponsePlaintext}; use crate::util; -pub struct Handshake { +use futures::{ + io::{ReadExact, Window, WriteAll}, + Future, +}; +use std::{ + pin::Pin, + task::{Context, Poll}, +}; +use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt}; + +use tokio_util::codec::{Decoder, Framed}; + +pub struct Handshake<'a, T> { keys: DHLocalKeys, - state: HandshakeState, + state: HandshakeState<'a, T>, } -enum HandshakeState { - ClientHello(WriteAll>), - APResponse(RecvPacket), - ClientResponse(Option, WriteAll>), +enum HandshakeState<'a, T> { + ClientHello(WriteAll<'a, T>), + APResponse(RecvPacket<'a, T, APResponseMessage>), + ClientResponse(Option, WriteAll<'a, T>), } -pub fn handshake(connection: T) -> Handshake { +pub fn handshake<'a, T: AsyncRead + AsyncWrite>(connection: T) -> Handshake<'a, T> { let local_keys = DHLocalKeys::random(&mut thread_rng()); let client_hello = client_hello(connection, local_keys.public_key()); @@ -37,23 +48,22 @@ pub fn handshake(connection: T) -> Handshake { } } -impl Future for Handshake { - type Item = Framed; - type Error = io::Error; +impl<'a, T: AsyncRead + AsyncWrite> Future for Handshake<'a, T> { + type Output = Result, io::Error>; - fn poll(&mut self) -> Poll { + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { use self::HandshakeState::*; loop { self.state = match self.state { ClientHello(ref mut write) => { - let (connection, accumulator) = try_ready!(write.poll()); + let (connection, accumulator) = ready!(write.poll()); let read = recv_packet(connection, accumulator); APResponse(read) } APResponse(ref mut read) => { - let (connection, message, accumulator) = try_ready!(read.poll()); + let (connection, message, accumulator) = ready!(read.poll()); let remote_key = message .get_challenge() .get_login_crypto_challenge() @@ -71,17 +81,17 @@ impl Future for Handshake { } ClientResponse(ref mut codec, ref mut write) => { - let (connection, _) = try_ready!(write.poll()); + let (connection, _) = ready!(write.poll()); let codec = codec.take().unwrap(); let framed = codec.framed(connection); - return Ok(Async::Ready(framed)); + return Poll::Ready(Ok(framed)); } } } } } -fn client_hello(connection: T, gc: Vec) -> WriteAll> { +fn client_hello<'a, T: AsyncWrite>(connection: T, gc: Vec) -> WriteAll<'a, T> { let mut packet = ClientHello::new(); packet .mut_build_info() @@ -109,10 +119,11 @@ fn client_hello(connection: T, gc: Vec) -> WriteAll(size).unwrap(); packet.write_to_vec(&mut buffer).unwrap(); - write_all(connection, buffer) + // write_all(connection, buffer) + connection.write_all(&buffer) } -fn client_response(connection: T, challenge: Vec) -> WriteAll> { +fn client_response<'a, T: AsyncWrite>(connection: T, challenge: Vec) -> WriteAll<'a, T> { let mut packet = ClientResponsePlaintext::new(); packet .mut_login_crypto_response() @@ -126,15 +137,16 @@ fn client_response(connection: T, challenge: Vec) -> WriteAll buffer.write_u32::(size).unwrap(); packet.write_to_vec(&mut buffer).unwrap(); - write_all(connection, buffer) + // write_all(connection, buffer) + connection.write_all(&buffer) } -enum RecvPacket { - Header(ReadExact>>, PhantomData), - Body(ReadExact>>, PhantomData), +enum RecvPacket<'a, T, M: Message> { + Header(ReadExact<'a, T>, PhantomData), + Body(ReadExact<'a, T>, PhantomData), } -fn recv_packet(connection: T, acc: Vec) -> RecvPacket +fn recv_packet<'a, T: AsyncRead, M>(connection: T, acc: Vec) -> RecvPacket<'a, T, M> where T: Read, M: Message, @@ -142,20 +154,19 @@ where RecvPacket::Header(read_into_accumulator(connection, 4, acc), PhantomData) } -impl Future for RecvPacket +impl<'a, T: AsyncRead, M> Future for RecvPacket<'a, T, M> where T: Read, M: Message, { - type Item = (T, M, Vec); - type Error = io::Error; + type Output = Result<(T, M, Vec), io::Error>; - fn poll(&mut self) -> Poll { + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { use self::RecvPacket::*; loop { *self = match *self { Header(ref mut read, _) => { - let (connection, header) = try_ready!(read.poll()); + let (connection, header) = ready!(read.poll()); let size = BigEndian::read_u32(header.as_ref()) as usize; let acc = header.into_inner(); @@ -164,29 +175,30 @@ where } Body(ref mut read, _) => { - let (connection, data) = try_ready!(read.poll()); + let (connection, data) = ready!(read.poll()); let message = protobuf::parse_from_bytes(data.as_ref()).unwrap(); let acc = data.into_inner(); - return Ok(Async::Ready((connection, message, acc))); + return Poll::Ready(Ok((connection, message, acc))); } } } } } -fn read_into_accumulator( +fn read_into_accumulator<'a, T: AsyncRead>( connection: T, size: usize, mut acc: Vec, -) -> ReadExact>> { +) -> ReadExact<'a, T> { let offset = acc.len(); acc.resize(offset + size, 0); let mut window = Window::new(acc); window.set_start(offset); - read_exact(connection, window) + // read_exact(connection, window) + connection.read_exact(window) } fn compute_keys(shared_secret: &[u8], packets: &[u8]) -> (Vec, Vec, Vec) { diff --git a/core/src/connection/mod.rs b/core/src/connection/mod.rs index c0e95f527..21550deeb 100644 --- a/core/src/connection/mod.rs +++ b/core/src/connection/mod.rs @@ -3,13 +3,18 @@ mod handshake; pub use self::codec::APCodec; pub use self::handshake::handshake; +use tokio::net::TcpStream; -use futures::{Future, Sink, Stream}; +use futures::{AsyncRead, AsyncWrite, Future, Sink, SinkExt, Stream, StreamExt}; use protobuf::{self, Message}; use std::io; use std::net::ToSocketAddrs; -use tokio::net::TcpStream; -use tokio_codec::Framed; +use tokio_util::codec::Framed; +// use futures::compat::{AsyncWrite01CompatExt, AsyncRead01CompatExt}; +// use tokio_util::compat::{self, Tokio02AsyncReadCompatExt, Tokio02AsyncWriteCompatExt}; +// use tokio_codec::Framed; +// use tokio_core::net::TcpStream; +// use tokio_core::reactor::Handle; use url::Url; use crate::authentication::Credentials; @@ -19,52 +24,46 @@ use crate::proxytunnel; pub type Transport = Framed; -pub fn connect( - addr: String, - proxy: &Option, -) -> Box> { - let (addr, connect_url) = match *proxy { +pub async fn connect(addr: String, proxy: &Option) -> Result { + let (addr, connect_url): (_, Option) = match *proxy { Some(ref url) => { - info!("Using proxy \"{}\"", url); - match url.to_socket_addrs().and_then(|mut iter| { - iter.next().ok_or(io::Error::new( - io::ErrorKind::NotFound, - "Can't resolve proxy server address", - )) - }) { - Ok(socket_addr) => (socket_addr, Some(addr)), - Err(error) => return Box::new(futures::future::err(error)), - } + unimplemented!() + // info!("Using proxy \"{}\"", url); + // + // let mut iter = url.to_socket_addrs()?; + // let socket_addr = iter.next().ok_or(io::Error::new( + // io::ErrorKind::NotFound, + // "Can't resolve proxy server address", + // ))?; + // (socket_addr, Some(addr)) } None => { - match addr.to_socket_addrs().and_then(|mut iter| { - iter.next().ok_or(io::Error::new( - io::ErrorKind::NotFound, - "Can't resolve server address", - )) - }) { - Ok(socket_addr) => (socket_addr, None), - Err(error) => return Box::new(futures::future::err(error)), - } + let mut iter = addr.to_socket_addrs()?; + let socket_addr = iter.next().ok_or(io::Error::new( + io::ErrorKind::NotFound, + "Can't resolve server address", + ))?; + (socket_addr, None) } }; - let socket = TcpStream::connect(&addr); + let connection = TcpStream::connect(&addr).await?; if let Some(connect_url) = connect_url { - let connection = socket - .and_then(move |socket| proxytunnel::connect(socket, &connect_url).and_then(handshake)); - Box::new(connection) + unimplemented!() + // let connection = proxytunnel::connect(connection, &connect_url).await?; + // let connection = handshake(connection).await?; + // Ok(connection) } else { - let connection = socket.and_then(handshake); - Box::new(connection) + let connection = handshake(connection).await?; + Ok(connection) } } -pub fn authenticate( - transport: Transport, +pub async fn authenticate( + mut transport: Transport, credentials: Credentials, device_id: String, -) -> Box> { +) -> Result<(Transport, Credentials), io::Error> { use crate::protocol::authentication::{APWelcome, ClientResponseEncrypted, CpuFamily, Os}; use crate::protocol::keyexchange::APLoginFailed; @@ -92,38 +91,39 @@ pub fn authenticate( packet.mut_system_info().set_device_id(device_id); packet.set_version_string(version::version_string()); - let cmd = 0xab; + let cmd: u8 = 0xab; let data = packet.write_to_bytes().unwrap(); - Box::new( - transport - .send((cmd, data)) - .and_then(|transport| transport.into_future().map_err(|(err, _stream)| err)) - .and_then(|(packet, transport)| match packet { - Some((0xac, data)) => { - let welcome_data: APWelcome = - protobuf::parse_from_bytes(data.as_ref()).unwrap(); - - let reusable_credentials = Credentials { - username: welcome_data.get_canonical_username().to_owned(), - auth_type: welcome_data.get_reusable_auth_credentials_type(), - auth_data: welcome_data.get_reusable_auth_credentials().to_owned(), - }; - - Ok((transport, reusable_credentials)) - } - - Some((0xad, data)) => { - let error_data: APLoginFailed = - protobuf::parse_from_bytes(data.as_ref()).unwrap(); - panic!( - "Authentication failed with reason: {:?}", - error_data.get_error_code() - ) - } - - Some((cmd, _)) => panic!("Unexpected packet {:?}", cmd), - None => panic!("EOF"), - }), - ) + transport.send((cmd, data)).await; + + let packet = transport.next().await; + // let (packet, transport) = transport + // .into_future() + // .map_err(|(err, _stream)| err) + // .await?; + match packet { + Some(Ok((0xac, data))) => { + let welcome_data: APWelcome = protobuf::parse_from_bytes(data.as_ref()).unwrap(); + + let reusable_credentials = Credentials { + username: welcome_data.get_canonical_username().to_owned(), + auth_type: welcome_data.get_reusable_auth_credentials_type(), + auth_data: welcome_data.get_reusable_auth_credentials().to_owned(), + }; + + Ok((transport, reusable_credentials)) + } + + Some(Ok((0xad, data))) => { + let error_data: APLoginFailed = protobuf::parse_from_bytes(data.as_ref()).unwrap(); + panic!( + "Authentication failed with reason: {:?}", + error_data.get_error_code() + ) + } + + Some(Ok((cmd, _))) => panic!("Unexpected packet {:?}", cmd), + Some(err @ Err(_)) => panic!("Packet error: {:?}", err), + None => panic!("EOF"), + } } diff --git a/core/src/keymaster.rs b/core/src/keymaster.rs index f2d7b772c..c7be11b02 100644 --- a/core/src/keymaster.rs +++ b/core/src/keymaster.rs @@ -1,4 +1,4 @@ -use futures::Future; +// use futures::Future; use serde_json; use crate::mercury::MercuryError; @@ -13,20 +13,22 @@ pub struct Token { pub scope: Vec, } -pub fn get_token( +pub async fn get_token( session: &Session, client_id: &str, scopes: &str, -) -> Box> { +) -> Result { let url = format!( "hm://keymaster/token/authenticated?client_id={}&scope={}", client_id, scopes ); - Box::new(session.mercury().get(url).map(move |response| { + + // Box::new(session.mercury().get(url).map(move |response| { + session.mercury().get(url).await.map(move |response| { let data = response.payload.first().expect("Empty payload"); let data = String::from_utf8(data.clone()).unwrap(); let token: Token = serde_json::from_str(&data).unwrap(); token - })) + }) } diff --git a/core/src/lib.rs b/core/src/lib.rs index 278478c1d..2d50ec708 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -1,7 +1,7 @@ #![cfg_attr(feature = "cargo-clippy", allow(unused_io_amount))] -#[macro_use] -extern crate error_chain; +// #[macro_use] +// extern crate error_chain; #[macro_use] extern crate futures; #[macro_use] @@ -30,8 +30,8 @@ extern crate serde_json; extern crate sha1; extern crate shannon; extern crate tokio; -extern crate tokio_codec; -extern crate tokio_io; +// extern crate tokio_codec; +// extern crate tokio_io; extern crate url; extern crate uuid; @@ -45,11 +45,11 @@ pub mod authentication; pub mod cache; pub mod channel; pub mod config; -mod connection; +pub mod connection; pub mod diffie_hellman; pub mod keymaster; pub mod mercury; -mod proxytunnel; +pub mod proxytunnel; pub mod session; pub mod spotify_id; pub mod util; diff --git a/core/src/mercury/mod.rs b/core/src/mercury/mod.rs index 20e3f0db1..7a80f44dd 100644 --- a/core/src/mercury/mod.rs +++ b/core/src/mercury/mod.rs @@ -2,12 +2,16 @@ use crate::protocol; use crate::util::url_encode; use byteorder::{BigEndian, ByteOrder}; use bytes::Bytes; -use futures::sync::{mpsc, oneshot}; -use futures::{Async, Future, Poll}; use protobuf; use std::collections::HashMap; use std::mem; +use futures::{ + channel::{mpsc, oneshot}, + Future, FutureExt, +}; +use std::task::Poll; + use crate::util::SeqGenerator; mod types; @@ -33,14 +37,13 @@ pub struct MercuryPending { pub struct MercuryFuture(oneshot::Receiver>); impl Future for MercuryFuture { - type Item = T; - type Error = MercuryError; + type Output = Result; - fn poll(&mut self) -> Poll { + fn poll(&mut self) -> Poll { match self.0.poll() { - Ok(Async::Ready(Ok(value))) => Ok(Async::Ready(value)), - Ok(Async::Ready(Err(err))) => Err(err), - Ok(Async::NotReady) => Ok(Async::NotReady), + Poll::Ready(Ok(Ok(value))) => Poll::Ready(Ok(value)), + Poll::Ready(Ok(Err(err))) => Err(err), + Poll::Pending => Poll::Pending, Err(oneshot::Canceled) => Err(MercuryError), } } @@ -98,11 +101,10 @@ impl MercuryManager { MercurySender::new(self.clone(), uri.into()) } - pub fn subscribe>( + pub async fn subscribe>( &self, uri: T, - ) -> Box, Error = MercuryError>> - { + ) -> Result, MercuryError> { let uri = uri.into(); let request = self.request(MercuryRequest { method: MercuryMethod::SUB, @@ -112,7 +114,7 @@ impl MercuryManager { }); let manager = self.clone(); - Box::new(request.map(move |response| { + request.await.map(move |response| { let (tx, rx) = mpsc::unbounded(); manager.lock(move |inner| { @@ -137,7 +139,7 @@ impl MercuryManager { }); rx - })) + }) } pub(crate) fn dispatch(&self, cmd: u8, mut data: Bytes) { diff --git a/core/src/mercury/sender.rs b/core/src/mercury/sender.rs index f00235ef9..f406a52ba 100644 --- a/core/src/mercury/sender.rs +++ b/core/src/mercury/sender.rs @@ -1,7 +1,11 @@ -use futures::{Async, AsyncSink, Future, Poll, Sink, StartSend}; +use futures::{Future, Sink}; use std::collections::VecDeque; use super::*; +use std::{ + pin::Pin, + task::{Context, Poll}, +}; pub struct MercurySender { mercury: MercuryManager, @@ -30,25 +34,23 @@ impl Clone for MercurySender { } } -impl Sink for MercurySender { - type SinkItem = Vec; - type SinkError = MercuryError; +type SinkItem = Vec; +impl Sink for MercurySender { + type Error = MercuryError; - fn start_send(&mut self, item: Self::SinkItem) -> StartSend { + fn start_send(self: Pin<&mut Self>, item: SinkItem) -> Result<(), Self::Error> { let task = self.mercury.send(self.uri.clone(), item); self.pending.push_back(task); - Ok(AsyncSink::Ready) + Poll::Ready(Ok(())) } - fn poll_complete(&mut self) -> Poll<(), Self::SinkError> { + fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { loop { match self.pending.front_mut() { Some(task) => { - try_ready!(task.poll()); - } - None => { - return Ok(Async::Ready(())); + ready!(task.poll()); } + None => return Poll::Ready(Ok(())), } self.pending.pop_front(); } diff --git a/core/src/proxytunnel.rs b/core/src/proxytunnel.rs index e8fb13735..fbc17f632 100644 --- a/core/src/proxytunnel.rs +++ b/core/src/proxytunnel.rs @@ -1,49 +1,61 @@ use std::io; use std::str::FromStr; -use futures::{Async, Future, Poll}; use httparse; use hyper::Uri; -use tokio_io::io::{read, write_all, Read, Window, WriteAll}; -use tokio_io::{AsyncRead, AsyncWrite}; - -pub struct ProxyTunnel { - state: ProxyState, +// use tokio_io::io::{read, write_all, Read, Window, WriteAll}; +// use tokio_io::{AsyncRead, AsyncWrite}; + +use futures::{ + io::{Read, Window, WriteAll}, + AsyncRead, AsyncWrite, Future, +}; +use std::{ + pin::Pin, + task::{Context, Poll}, +}; +// use tokio::io::{AsyncReadExt, AsyncWriteExt}; + +pub struct ProxyTunnel<'a, T> { + state: ProxyState<'a, T>, } -enum ProxyState { - ProxyConnect(WriteAll>), - ProxyResponse(Read>>), +enum ProxyState<'a, T> { + ProxyConnect(WriteAll<'a, T>), + ProxyResponse(Read<'a, T>), } -pub fn connect(connection: T, connect_url: &str) -> ProxyTunnel { +pub fn connect<'a, T: AsyncRead + AsyncWrite>( + connection: T, + connect_url: &str, +) -> ProxyTunnel<'a, T> { let proxy = proxy_connect(connection, connect_url); ProxyTunnel { state: ProxyState::ProxyConnect(proxy), } } -impl Future for ProxyTunnel { - type Item = T; - type Error = io::Error; +impl<'a, T: AsyncRead + AsyncWrite> Future for ProxyTunnel<'a, T> { + type Output = Result; - fn poll(&mut self) -> Poll { + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { use self::ProxyState::*; loop { self.state = match self.state { ProxyConnect(ref mut write) => { - let (connection, mut accumulator) = try_ready!(write.poll()); + let (connection, mut accumulator) = ready!(write.poll()); let capacity = accumulator.capacity(); accumulator.resize(capacity, 0); let window = Window::new(accumulator); - let read = read(connection, window); - ProxyResponse(read) + // let read = read(connection, window); + // ProxyResponse(read) + ProxyResponse(connection.read(window)) } ProxyResponse(ref mut read_f) => { - let (connection, mut window, bytes_read) = try_ready!(read_f.poll()); + let (connection, mut window, bytes_read) = ready!(read_f.poll()); if bytes_read == 0 { return Err(io::Error::new(io::ErrorKind::Other, "Early EOF from proxy")); @@ -65,7 +77,7 @@ impl Future for ProxyTunnel { if let Some(code) = response.code { if code == 200 { // Proxy says all is well - return Ok(Async::Ready(connection)); + return Poll::Ready(connection); } else { let reason = response.reason.unwrap_or("no reason"); let msg = format!("Proxy responded with {}: {}", code, reason); @@ -87,8 +99,9 @@ impl Future for ProxyTunnel { } // We did not get a full header window.set_start(data_end); - let read = read(connection, window); - ProxyResponse(read) + // let read = read(connection, window); + // ProxyResponse(read) + ProxyResponse(connection.read(window)) } } } @@ -96,7 +109,7 @@ impl Future for ProxyTunnel { } } -fn proxy_connect(connection: T, connect_url: &str) -> WriteAll> { +fn proxy_connect(connection: T, connect_url: &str) -> WriteAll { let uri = Uri::from_str(connect_url).unwrap(); let buffer = format!( "CONNECT {0}:{1} HTTP/1.1\r\n\ @@ -106,5 +119,6 @@ fn proxy_connect(connection: T, connect_url: &str) -> WriteAll); +// TODO: Define better errors! +type Result = std::result::Result>; + impl Session { - pub fn connect( + pub async fn connect( config: SessionConfig, credentials: Credentials, cache: Option, handle: Handle, - ) -> Box> { - let access_point = apresolve_or_fallback::(&config.proxy, &config.ap_port); - - let proxy = config.proxy.clone(); - let connection = access_point.and_then(move |addr| { - info!("Connecting to AP \"{}\"", addr); - connection::connect(addr, &proxy) - }); - - let device_id = config.device_id.clone(); - let authentication = connection.and_then(move |connection| { - connection::authenticate(connection, credentials, device_id) - }); - - let result = authentication.map(move |(transport, reusable_credentials)| { - info!("Authenticated as \"{}\" !", reusable_credentials.username); - if let Some(ref cache) = cache { - cache.save_credentials(&reusable_credentials); - } - - let (session, task) = Session::create( - &handle, - transport, - config, - cache, - reusable_credentials.username.clone(), - ); - - current_thread::spawn(task.map_err(|e| { - error!("SessionError: {}", e.to_string()); - std::process::exit(0); - })); - - session - }); - - Box::new(result) + ) -> Result { + unimplemented!() + // let access_point_addr = + // apresolve_or_fallback::(&config.proxy, &config.ap_port).await?; + // + // let proxy = config.proxy.clone(); + // info!("Connecting to AP \"{}\"", access_point_addr); + // let connection = connection::connect(access_point_addr, &proxy); + // + // let device_id = config.device_id.clone(); + // let authentication = connection.and_then(move |connection| { + // connection::authenticate(connection, credentials, device_id) + // }); + // + // let result = authentication.map(move |(transport, reusable_credentials)| { + // info!("Authenticated as \"{}\" !", reusable_credentials.username); + // if let Some(ref cache) = cache { + // cache.save_credentials(&reusable_credentials); + // } + // + // let (session, task) = Session::create( + // &handle, + // transport, + // config, + // cache, + // reusable_credentials.username.clone(), + // ); + // + // tokio::spawn(task.map_err(|e| { + // error!("SessionError: {}", e.to_string()); + // std::process::exit(0); + // })); + // + // session + // }); + // + // result } fn create( @@ -97,7 +115,7 @@ impl Session { config: SessionConfig, cache: Option, username: String, - ) -> (Session, Box>) { + ) -> (Session, Box>>) { let (sink, stream) = transport.split(); let (sender_tx, sender_rx) = mpsc::unbounded(); @@ -160,7 +178,7 @@ impl Session { // Spawn a future directly pub fn spawn(&self, f: F) where - F: Future + Send + 'static, + F: Future + Send + 'static, { let handle = self.0.handle.lock().unwrap(); let spawn_res = handle.spawn(f); @@ -293,34 +311,35 @@ impl Drop for SessionInternal { } } +// type SErr = ::std::fmt::Debug; + struct DispatchTask(S, SessionWeak) where - S: Stream; + S: Stream>; impl Future for DispatchTask where - S: Stream, - ::Error: ::std::fmt::Debug, + // SErr: ::std::fmt::Debug, + S: Stream>, { - type Item = (); - type Error = S::Error; + type Output = Result<((), ())>; - fn poll(&mut self) -> Poll { + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { let session = match self.1.try_upgrade() { Some(session) => session, - None => return Ok(Async::Ready(())), + None => return Poll::Ready(()), }; loop { - let (cmd, data) = match self.0.poll() { - Ok(Async::Ready(Some(t))) => t, - Ok(Async::Ready(None)) => { + let (cmd, data) = match self.unwrap().0.poll() { + Poll::Ready(Ok(Some(t))) => t, + Poll::Ready(Ok(None)) => { warn!("Connection to server closed."); session.shutdown(); - return Ok(Async::Ready(())); + return Ok(Poll::Ready(())); } - Ok(Async::NotReady) => return Ok(Async::NotReady), - Err(e) => { + Poll::Pending => return Poll::Pending, + Poll::Ready(Err(e)) => { session.shutdown(); return Err(From::from(e)); } @@ -333,7 +352,7 @@ where impl Drop for DispatchTask where - S: Stream, + S: Stream>, { fn drop(&mut self) { debug!("drop Dispatch"); diff --git a/core/tests/connect.rs b/core/tests/connect.rs new file mode 100644 index 000000000..388db25c4 --- /dev/null +++ b/core/tests/connect.rs @@ -0,0 +1,23 @@ +use env_logger; +use std::env; +use tokio::runtime::Runtime; + +use librespot_core::{apresolve::apresolve_or_fallback, connection}; + +// TODO: Rewrite this into an actual test instead of this wonder +fn main() { + env_logger::init(); + let mut rt = Runtime::new().unwrap(); + + let args: Vec<_> = env::args().collect(); + if args.len() != 4 { + println!("Usage: {} USERNAME PASSWORD PLAYLIST", args[0]); + } + // let username = args[1].to_owned(); + // let password = args[2].to_owned(); + + let ap = rt.block_on(apresolve_or_fallback(&None, &Some(80))); + + println!("AP: {:?}", ap); + let connection = rt.block_on(connection::connect(&None)); +} From 94fc0a12da8c9bdc9358a7c255e138a7aebb734b Mon Sep 17 00:00:00 2001 From: ashthespy Date: Sat, 23 Jan 2021 22:21:42 +0000 Subject: [PATCH 08/75] [Core/connection] Refactor to async/await --- core/Cargo.toml | 2 +- core/src/connection/codec.rs | 2 +- core/src/connection/handshake.rs | 230 ++++++++++--------------------- core/src/connection/mod.rs | 64 ++++----- core/tests/connect.rs | 58 +++++--- 5 files changed, 141 insertions(+), 215 deletions(-) diff --git a/core/Cargo.toml b/core/Cargo.toml index 8c9475a61..a76b45ab3 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -15,7 +15,7 @@ version = "0.1.3" [dependencies] base64 = "0.13" byteorder = "1.3" -bytes = "0.4" +bytes = "0.5" error-chain = { version = "0.12", default_features = false } futures = {version = "0.3",features =["unstable","bilock"]} httparse = "1.3" diff --git a/core/src/connection/codec.rs b/core/src/connection/codec.rs index 47e116308..1417a5c46 100644 --- a/core/src/connection/codec.rs +++ b/core/src/connection/codec.rs @@ -45,7 +45,7 @@ impl Encoder for APCodec { buf.reserve(3 + payload.len()); buf.put_u8(cmd); - buf.put_u16_be(payload.len() as u16); + buf.put_u16(payload.len() as u16); buf.extend_from_slice(&payload); self.encode_cipher.nonce_u32(self.encode_nonce); diff --git a/core/src/connection/handshake.rs b/core/src/connection/handshake.rs index 512f61cd4..39bce7c40 100644 --- a/core/src/connection/handshake.rs +++ b/core/src/connection/handshake.rs @@ -1,97 +1,71 @@ -use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; +use super::codec::APCodec; +use crate::{ + diffie_hellman::DHLocalKeys, + protocol, + protocol::keyexchange::{APResponseMessage, ClientHello, ClientResponsePlaintext}, + util, +}; + use hmac::{Hmac, Mac}; use protobuf::{self, Message}; use rand::thread_rng; use sha1::Sha1; -use std::io::{self, Read}; -use std::marker::PhantomData; -// use tokio_codec::{Decoder, Framed}; -// use tokio_io::io::{read_exact, write_all, ReadExact, Window, WriteAll}; -// use tokio_io::{AsyncRead, AsyncWrite}; - -use super::codec::APCodec; -use crate::diffie_hellman::DHLocalKeys; -use crate::protocol; -use crate::protocol::keyexchange::{APResponseMessage, ClientHello, ClientResponsePlaintext}; -use crate::util; - -use futures::{ - io::{ReadExact, Window, WriteAll}, - Future, -}; -use std::{ - pin::Pin, - task::{Context, Poll}, -}; -use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt}; - +use std::{io, marker::Unpin}; +use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; use tokio_util::codec::{Decoder, Framed}; -pub struct Handshake<'a, T> { - keys: DHLocalKeys, - state: HandshakeState<'a, T>, -} - -enum HandshakeState<'a, T> { - ClientHello(WriteAll<'a, T>), - APResponse(RecvPacket<'a, T, APResponseMessage>), - ClientResponse(Option, WriteAll<'a, T>), -} +// struct handshake { +// keys: DHLocalKeys, +// connection: T, +// accumulator: Vec, +// } -pub fn handshake<'a, T: AsyncRead + AsyncWrite>(connection: T) -> Handshake<'a, T> { +pub async fn handshake( + mut connection: T, +) -> Result, io::Error> { let local_keys = DHLocalKeys::random(&mut thread_rng()); - let client_hello = client_hello(connection, local_keys.public_key()); - - Handshake { - keys: local_keys, - state: HandshakeState::ClientHello(client_hello), - } + // Send ClientHello + let client_hello: Vec = client_hello(local_keys.public_key()).await?; + connection.write_all(&client_hello).await?; + + // Receive APResponseMessage + let size = connection.read_u32().await?; + let mut buffer = Vec::with_capacity(size as usize - 4); + let bytes = connection.read_buf(&mut buffer).await?; + let message = protobuf::parse_from_bytes::(&buffer[..bytes])?; + + let mut accumulator = client_hello.clone(); + accumulator.extend_from_slice(&size.to_be_bytes()); + accumulator.extend_from_slice(&buffer); + let remote_key = message + .get_challenge() + .get_login_crypto_challenge() + .get_diffie_hellman() + .get_gs() + .to_owned(); + + // Solve the challenge + let shared_secret = local_keys.shared_secret(&remote_key); + let (challenge, send_key, recv_key) = compute_keys(&shared_secret, &accumulator); + let codec = APCodec::new(&send_key, &recv_key); + + let buffer: Vec = client_response(challenge).await?; + connection.write_all(&buffer).await?; + let framed = codec.framed(connection); + Ok(framed) } -impl<'a, T: AsyncRead + AsyncWrite> Future for Handshake<'a, T> { - type Output = Result, io::Error>; - - fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { - use self::HandshakeState::*; - loop { - self.state = match self.state { - ClientHello(ref mut write) => { - let (connection, accumulator) = ready!(write.poll()); - - let read = recv_packet(connection, accumulator); - APResponse(read) - } - - APResponse(ref mut read) => { - let (connection, message, accumulator) = ready!(read.poll()); - let remote_key = message - .get_challenge() - .get_login_crypto_challenge() - .get_diffie_hellman() - .get_gs() - .to_owned(); - - let shared_secret = self.keys.shared_secret(&remote_key); - let (challenge, send_key, recv_key) = - compute_keys(&shared_secret, &accumulator); - let codec = APCodec::new(&send_key, &recv_key); - - let write = client_response(connection, challenge); - ClientResponse(Some(codec), write) - } - - ClientResponse(ref mut codec, ref mut write) => { - let (connection, _) = ready!(write.poll()); - let codec = codec.take().unwrap(); - let framed = codec.framed(connection); - return Poll::Ready(Ok(framed)); - } - } - } - } -} - -fn client_hello<'a, T: AsyncWrite>(connection: T, gc: Vec) -> WriteAll<'a, T> { +// async fn recv_packet( +// mut connection: T, +// ) -> Result<(Message, &Vec), io::Error> { +// let size = connection.read_u32().await?; +// let mut buffer = Vec::with_capacity(size as usize - 4); +// let bytes = connection.read_buf(&mut buffer).await?; +// let proto = protobuf::parse_from_bytes(&buffer[..bytes])?; +// Ok(proto) +// } + +async fn client_hello(gc: Vec) -> Result, io::Error> { let mut packet = ClientHello::new(); packet .mut_build_info() @@ -99,7 +73,7 @@ fn client_hello<'a, T: AsyncWrite>(connection: T, gc: Vec) -> WriteAll<'a, T packet .mut_build_info() .set_platform(protocol::keyexchange::Platform::PLATFORM_LINUX_X86); - packet.mut_build_info().set_version(109800078); + packet.mut_build_info().set_version(109_800_078); packet .mut_cryptosuites_supported() .push(protocol::keyexchange::Cryptosuite::CRYPTO_SUITE_SHANNON); @@ -114,16 +88,15 @@ fn client_hello<'a, T: AsyncWrite>(connection: T, gc: Vec) -> WriteAll<'a, T packet.set_client_nonce(util::rand_vec(&mut thread_rng(), 0x10)); packet.set_padding(vec![0x1e]); - let mut buffer = vec![0, 4]; let size = 2 + 4 + packet.compute_size(); - buffer.write_u32::(size).unwrap(); - packet.write_to_vec(&mut buffer).unwrap(); - - // write_all(connection, buffer) - connection.write_all(&buffer) + let mut buffer = Vec::with_capacity(size as usize); + buffer.extend(&[0, 4]); + buffer.write_u32(size).await?; + buffer.extend(packet.write_to_bytes()?); + Ok(buffer) } -fn client_response<'a, T: AsyncWrite>(connection: T, challenge: Vec) -> WriteAll<'a, T> { +async fn client_response(challenge: Vec) -> Result, io::Error> { let mut packet = ClientResponsePlaintext::new(); packet .mut_login_crypto_response() @@ -132,73 +105,14 @@ fn client_response<'a, T: AsyncWrite>(connection: T, challenge: Vec) -> Writ packet.mut_pow_response(); packet.mut_crypto_response(); - let mut buffer = vec![]; + // let mut buffer = vec![]; let size = 4 + packet.compute_size(); - buffer.write_u32::(size).unwrap(); - packet.write_to_vec(&mut buffer).unwrap(); - - // write_all(connection, buffer) - connection.write_all(&buffer) -} - -enum RecvPacket<'a, T, M: Message> { - Header(ReadExact<'a, T>, PhantomData), - Body(ReadExact<'a, T>, PhantomData), -} - -fn recv_packet<'a, T: AsyncRead, M>(connection: T, acc: Vec) -> RecvPacket<'a, T, M> -where - T: Read, - M: Message, -{ - RecvPacket::Header(read_into_accumulator(connection, 4, acc), PhantomData) -} - -impl<'a, T: AsyncRead, M> Future for RecvPacket<'a, T, M> -where - T: Read, - M: Message, -{ - type Output = Result<(T, M, Vec), io::Error>; - - fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { - use self::RecvPacket::*; - loop { - *self = match *self { - Header(ref mut read, _) => { - let (connection, header) = ready!(read.poll()); - let size = BigEndian::read_u32(header.as_ref()) as usize; - - let acc = header.into_inner(); - let read = read_into_accumulator(connection, size - 4, acc); - RecvPacket::Body(read, PhantomData) - } - - Body(ref mut read, _) => { - let (connection, data) = ready!(read.poll()); - let message = protobuf::parse_from_bytes(data.as_ref()).unwrap(); - - let acc = data.into_inner(); - return Poll::Ready(Ok((connection, message, acc))); - } - } - } - } -} - -fn read_into_accumulator<'a, T: AsyncRead>( - connection: T, - size: usize, - mut acc: Vec, -) -> ReadExact<'a, T> { - let offset = acc.len(); - acc.resize(offset + size, 0); - - let mut window = Window::new(acc); - window.set_start(offset); - - // read_exact(connection, window) - connection.read_exact(window) + let mut buffer = Vec::with_capacity(size as usize); + buffer.write_u32(size).await?; + // This seems to reallocate + // packet.write_to_vec(&mut buffer)?; + buffer.extend(packet.write_to_bytes()?); + Ok(buffer) } fn compute_keys(shared_secret: &[u8], packets: &[u8]) -> (Vec, Vec, Vec) { diff --git a/core/src/connection/mod.rs b/core/src/connection/mod.rs index 21550deeb..6540f4f52 100644 --- a/core/src/connection/mod.rs +++ b/core/src/connection/mod.rs @@ -1,48 +1,39 @@ mod codec; mod handshake; -pub use self::codec::APCodec; -pub use self::handshake::handshake; -use tokio::net::TcpStream; +pub use self::{codec::APCodec, handshake::handshake}; +use crate::{authentication::Credentials, version}; -use futures::{AsyncRead, AsyncWrite, Future, Sink, SinkExt, Stream, StreamExt}; +use futures::{SinkExt, StreamExt}; use protobuf::{self, Message}; -use std::io; -use std::net::ToSocketAddrs; +use std::{io, net::ToSocketAddrs}; +use tokio::net::TcpStream; use tokio_util::codec::Framed; -// use futures::compat::{AsyncWrite01CompatExt, AsyncRead01CompatExt}; -// use tokio_util::compat::{self, Tokio02AsyncReadCompatExt, Tokio02AsyncWriteCompatExt}; -// use tokio_codec::Framed; -// use tokio_core::net::TcpStream; -// use tokio_core::reactor::Handle; use url::Url; -use crate::authentication::Credentials; -use crate::version; - -use crate::proxytunnel; +// use crate::proxytunnel; pub type Transport = Framed; pub async fn connect(addr: String, proxy: &Option) -> Result { let (addr, connect_url): (_, Option) = match *proxy { Some(ref url) => { - unimplemented!() - // info!("Using proxy \"{}\"", url); - // - // let mut iter = url.to_socket_addrs()?; - // let socket_addr = iter.next().ok_or(io::Error::new( - // io::ErrorKind::NotFound, - // "Can't resolve proxy server address", - // ))?; - // (socket_addr, Some(addr)) + info!("Using proxy \"{}\"", url); + + let mut iter = url.to_socket_addrs()?; + let socket_addr = iter.next().ok_or_else(|| { + io::Error::new( + io::ErrorKind::NotFound, + "Can't resolve proxy server address", + ) + })?; + (socket_addr, Some(addr)) } None => { let mut iter = addr.to_socket_addrs()?; - let socket_addr = iter.next().ok_or(io::Error::new( - io::ErrorKind::NotFound, - "Can't resolve server address", - ))?; + let socket_addr = iter.next().ok_or_else(|| { + io::Error::new(io::ErrorKind::NotFound, "Can't resolve server address") + })?; (socket_addr, None) } }; @@ -54,8 +45,7 @@ pub async fn connect(addr: String, proxy: &Option) -> Result Result<(Transport, Credentials), io::Error> { - use crate::protocol::authentication::{APWelcome, ClientResponseEncrypted, CpuFamily, Os}; - use crate::protocol::keyexchange::APLoginFailed; + use crate::protocol::{ + authentication::{APWelcome, ClientResponseEncrypted, CpuFamily, Os}, + keyexchange::APLoginFailed, + }; let mut packet = ClientResponseEncrypted::new(); packet @@ -94,13 +86,11 @@ pub async fn authenticate( let cmd: u8 = 0xab; let data = packet.write_to_bytes().unwrap(); - transport.send((cmd, data)).await; + transport.send((cmd, data)).await?; let packet = transport.next().await; - // let (packet, transport) = transport - // .into_future() - // .map_err(|(err, _stream)| err) - // .await?; + + // TODO: Don't panic? match packet { Some(Ok((0xac, data))) => { let welcome_data: APWelcome = protobuf::parse_from_bytes(data.as_ref()).unwrap(); diff --git a/core/tests/connect.rs b/core/tests/connect.rs index 388db25c4..abc75a0bd 100644 --- a/core/tests/connect.rs +++ b/core/tests/connect.rs @@ -1,23 +1,45 @@ -use env_logger; -use std::env; -use tokio::runtime::Runtime; +use futures::future::TryFutureExt; +use librespot_core::*; +use tokio::runtime; -use librespot_core::{apresolve::apresolve_or_fallback, connection}; - -// TODO: Rewrite this into an actual test instead of this wonder -fn main() { - env_logger::init(); - let mut rt = Runtime::new().unwrap(); - - let args: Vec<_> = env::args().collect(); - if args.len() != 4 { - println!("Usage: {} USERNAME PASSWORD PLAYLIST", args[0]); +#[cfg(test)] +mod tests { + use super::*; + // Test AP Resolve + use apresolve::apresolve_or_fallback; + #[test] + fn test_ap_resolve() { + let mut rt = runtime::Runtime::new().unwrap(); + let ap = rt.block_on(apresolve_or_fallback(&None, &Some(80))); + println!("AP: {:?}", ap); } - // let username = args[1].to_owned(); - // let password = args[2].to_owned(); - let ap = rt.block_on(apresolve_or_fallback(&None, &Some(80))); + // Test connect + use authentication::Credentials; + use config::SessionConfig; + use connection; + #[test] + fn test_connection() { + println!("Running connection test"); + let mut rt = runtime::Runtime::new().unwrap(); + let access_point_addr = rt.block_on(apresolve_or_fallback(&None, &None)).unwrap(); + let credentials = Credentials::with_password(String::from("test"), String::from("test")); + let session_config = SessionConfig::default(); + let proxy = None; - println!("AP: {:?}", ap); - let connection = rt.block_on(connection::connect(&None)); + println!("Connecting to AP \"{}\"", access_point_addr); + let connection = connection::connect(access_point_addr, &proxy); + + let device_id = session_config.device_id.clone(); + let authentication = connection.and_then(move |connection| { + connection::authenticate(connection, credentials, device_id) + }); + match rt.block_on(authentication) { + Ok((_transport, reusable_credentials)) => { + println!("Authenticated as \"{}\" !", reusable_credentials.username) + } + // TODO assert that we get BadCredentials once we don't panic + Err(e) => println!("ConnectError: {:?}", e), + } + } } From c273d51a1df00d73935538c3952ef016216fc131 Mon Sep 17 00:00:00 2001 From: ashthespy Date: Sat, 23 Jan 2021 22:21:42 +0000 Subject: [PATCH 09/75] [AudioKeyManager] Convert to async --- core/Cargo.toml | 1 + core/src/audio_key.rs | 41 +++++++++++++++-------------------------- 2 files changed, 16 insertions(+), 26 deletions(-) diff --git a/core/Cargo.toml b/core/Cargo.toml index a76b45ab3..077efe0ae 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -14,6 +14,7 @@ version = "0.1.3" [dependencies] base64 = "0.13" +thiserror = "1.0" byteorder = "1.3" bytes = "0.5" error-chain = { version = "0.12", default_features = false } diff --git a/core/src/audio_key.rs b/core/src/audio_key.rs index 39eef721e..976361d02 100644 --- a/core/src/audio_key.rs +++ b/core/src/audio_key.rs @@ -1,13 +1,9 @@ use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; use bytes::Bytes; +use futures::channel::oneshot; use std::collections::HashMap; use std::io::Write; - -use futures::{channel::oneshot, Future}; -use std::{ - pin::Pin, - task::{Context, Poll}, -}; +use thiserror::Error; use crate::spotify_id::{FileId, SpotifyId}; use crate::util::SeqGenerator; @@ -15,8 +11,13 @@ use crate::util::SeqGenerator; #[derive(Debug, Hash, PartialEq, Eq, Copy, Clone)] pub struct AudioKey(pub [u8; 16]); -#[derive(Debug, Hash, PartialEq, Eq, Copy, Clone)] -pub struct AudioKeyError; +#[derive(Error, Debug)] +pub enum AudioKeyError { + #[error("AudioKey sender disconnected")] + Cancelled(#[from] oneshot::Canceled), + #[error("Unknown server response: `{0:?}`")] + UnknownResponse(Vec), +} component! { AudioKeyManager : AudioKeyManagerInner { @@ -44,14 +45,16 @@ impl AudioKeyManager { data.as_ref()[0], data.as_ref()[1] ); - let _ = sender.send(Err(AudioKeyError)); + let _ = sender.send(Err(AudioKeyError::UnknownResponse( + data.as_ref()[..1].to_vec(), + ))); } - _ => (), + _ => warn!("Unexpected audioKey response: 0x{:x?} {:?}", cmd, data), } } } - pub fn request(&self, track: SpotifyId, file: FileId) -> AudioKeyFuture { + pub async fn request(&self, track: SpotifyId, file: FileId) -> Result { let (tx, rx) = oneshot::channel(); let seq = self.lock(move |inner| { @@ -61,7 +64,7 @@ impl AudioKeyManager { }); self.send_key_request(seq, track, file); - AudioKeyFuture(rx) + rx.await? } fn send_key_request(&self, seq: u32, track: SpotifyId, file: FileId) { @@ -74,17 +77,3 @@ impl AudioKeyManager { self.session().send_packet(0xc, data) } } - -pub struct AudioKeyFuture(oneshot::Receiver>); -impl Future for AudioKeyFuture { - type Output = Result; - - fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { - match self.0.poll() { - Poll::Ready(Ok(Ok(value))) => Poll::Ready(Ok(value)), - Poll::Ready(Ok(Err(err))) => Err(err), - Poll::Pending => Poll::Pending, - Err(oneshot::Canceled) => Err(AudioKeyError), - } - } -} From 20dd94fe2079e998480a72e04acd50ab46a2393b Mon Sep 17 00:00:00 2001 From: ashthespy Date: Sat, 23 Jan 2021 22:21:42 +0000 Subject: [PATCH 10/75] Fix tokio dependency in main --- Cargo.lock | 3312 +++++++++++++++++++++++++++++----------------------- Cargo.toml | 4 +- 2 files changed, 1859 insertions(+), 1457 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c4fc5c43f..470dd3245 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,3506 +2,3908 @@ # It is not intended for manual editing. [[package]] name = "addr2line" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7" dependencies = [ - "gimli 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gimli", ] [[package]] name = "adler" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" [[package]] name = "adler32" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" [[package]] name = "aes" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54eb1d8fe354e5fc611daf4f2ea97dd45a765f4f1e4512306ec183ae2e8f20c9" dependencies = [ - "aes-soft 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "aes-soft", + "aesni", + "block-cipher-trait", ] [[package]] name = "aes-ctr" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2e5b0458ea3beae0d1d8c0f3946564f8e10f90646cf78c06b4351052058d1ee" dependencies = [ - "aes-soft 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ctr 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "stream-cipher 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "aes-soft", + "aesni", + "ctr", + "stream-cipher", ] [[package]] name = "aes-soft" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfd7e7ae3f9a1fb5c03b389fc6bb9a51400d0c13053f0dca698c832bfd893a0d" dependencies = [ - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "block-cipher-trait", + "byteorder", + "opaque-debug", ] [[package]] name = "aesni" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100" dependencies = [ - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "stream-cipher 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "block-cipher-trait", + "opaque-debug", + "stream-cipher", ] [[package]] name = "alsa" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4a0d4ebc8b23041c5de9bc9aee13b4bad844a589479701f31a5934cfe4aeb32" dependencies = [ - "alsa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "nix 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "alsa-sys 0.1.2", + "bitflags 0.9.1", + "libc", + "nix 0.9.0", ] [[package]] name = "alsa" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb213f6b3e4b1480a60931ca2035794aa67b73103d254715b1db7b70dcb3c934" dependencies = [ - "alsa-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "alsa-sys 0.3.1", + "bitflags 1.2.1", + "libc", + "nix 0.15.0", ] [[package]] name = "alsa-sys" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0edcbbf9ef68f15ae1b620f722180b82a98b6f0628d30baa6b8d2a5abc87d58" dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "pkg-config", ] [[package]] name = "alsa-sys" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527" dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "pkg-config", ] [[package]] name = "anyhow" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "arc-swap" -version = "0.4.7" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1" [[package]] name = "ascii" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi", + "libc", + "winapi 0.3.9", ] [[package]] name = "autocfg" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "backtrace" -version = "0.3.55" +version = "0.3.56" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d117600f438b1707d4e4ae15d3595657288f8235a0eb593e80ecc98ab34e1bc" dependencies = [ - "addr2line 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "object 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "addr2line", + "cfg-if 1.0.0", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", ] [[package]] -name = "base64" -version = "0.9.3" +name = "base-x" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" [[package]] name = "base64" -version = "0.10.1" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "safemem", ] [[package]] name = "base64" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" [[package]] name = "base64" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] name = "bindgen" -version = "0.53.3" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2da379dbebc0b76ef63ca68d8fc6e71c0f13e59432e0987e508c1820e6ab5239" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cexpr 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "clang-sys 0.29.3 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hash 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", ] [[package]] name = "bit-set" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de" dependencies = [ - "bit-vec 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bit-vec", ] [[package]] name = "bit-vec" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "block-buffer" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" dependencies = [ - "block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "block-padding", + "byte-tools", + "byteorder", + "generic-array", ] [[package]] name = "block-cipher-trait" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774" dependencies = [ - "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array", ] [[package]] name = "block-modes" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31aa8410095e39fdb732909fb5730a48d5bd7c2e3cd76bd1b07b3dbea130c529" dependencies = [ - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "block-cipher-trait", + "block-padding", ] [[package]] name = "block-padding" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" dependencies = [ - "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools", ] [[package]] name = "bumpalo" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f07aa6688c702439a1be0307b6a94dffe1168569e45b9500c1372bc580740d59" [[package]] name = "byte-tools" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "byteorder" -version = "1.3.4" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" [[package]] name = "bytes" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "either", + "iovec", ] [[package]] name = "bytes" version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" + +[[package]] +name = "bytes" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" [[package]] name = "cc" -version = "1.0.65" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" [[package]] name = "cesu8" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" [[package]] name = "cexpr" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" dependencies = [ - "nom 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "nom", ] [[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.13" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" dependencies = [ - "num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "num-integer", + "num-traits", + "time 0.1.43", + "winapi 0.3.9", ] [[package]] name = "chunked_transfer" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7477065d45a8fe57167bf3cf8bcd3729b54cfcb81cca49bda2d038ea89ae82ca" [[package]] name = "clang-sys" -version = "0.29.3" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0659001ab56b791be01d4b729c44376edc6718cf389a502e579b77b758f3296c" dependencies = [ - "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "glob", + "libc", + "libloading", ] [[package]] name = "cloudabi" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", ] [[package]] -name = "cloudabi" -version = "0.1.0" +name = "combine" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ascii", + "byteorder", + "either", + "memchr", + "unreachable", ] [[package]] name = "combine" -version = "3.8.1" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4369b5e4c0cddf64ad8981c0111e7df4f7078f4d6ba98fb31f2e17c4c57b7e" dependencies = [ - "ascii 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 1.0.1", + "memchr", ] [[package]] -name = "combine" -version = "4.4.0" +name = "const_fn" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6" + +[[package]] +name = "cookie" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784ad0fbab4f3e9cef09f20e0aea6000ae08d2cb98ac4c0abc53df18803d702f" dependencies = [ - "bytes 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-project-lite 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 2.1.0", + "time 0.2.25", + "version_check", ] [[package]] -name = "cookie" +name = "cookie_store" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3818dfca4b0cb5211a659bbcbb94225b7127407b2b135e650d717bfb78ab10d3" dependencies = [ - "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cookie", + "idna 0.2.0", + "log", + "publicsuffix", + "serde", + "serde_json", + "time 0.2.25", + "url 2.2.0", ] [[package]] name = "core-foundation-sys" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" [[package]] name = "coreaudio-rs" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f229761965dad3e9b11081668a6ea00f1def7aa46062321b5ec245b834f6e491" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "coreaudio-sys 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "coreaudio-sys", ] [[package]] name = "coreaudio-sys" -version = "0.2.5" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b7e3347be6a09b46aba228d6608386739fb70beff4f61e07422da87b0bb31fa" dependencies = [ - "bindgen 0.53.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bindgen", ] [[package]] name = "cpal" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05631e2089dfa5d3b6ea1cfbbfd092e2ee5deeb69698911bc976b28b746d3657" dependencies = [ - "alsa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "coreaudio-rs 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "jni 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "mach 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ndk 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ndk-glue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "oboe 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", - "stdweb 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", - "web-sys 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "alsa 0.4.3", + "core-foundation-sys", + "coreaudio-rs", + "jni 0.17.0", + "js-sys", + "lazy_static", + "libc", + "mach", + "ndk", + "ndk-glue", + "nix 0.15.0", + "oboe", + "parking_lot 0.11.1", + "stdweb 0.1.3", + "thiserror", + "web-sys", + "winapi 0.3.9", ] [[package]] name = "crc32fast" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" dependencies = [ - "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", ] [[package]] name = "crossbeam-deque" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" dependencies = [ - "crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-epoch", + "crossbeam-utils 0.7.2", + "maybe-uninit", ] [[package]] name = "crossbeam-epoch" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", + "cfg-if 0.1.10", + "crossbeam-utils 0.7.2", + "lazy_static", + "maybe-uninit", + "memoffset", + "scopeguard", ] [[package]] name = "crossbeam-queue" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" dependencies = [ - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6", ] [[package]] name = "crossbeam-queue" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10", + "crossbeam-utils 0.7.2", + "maybe-uninit", ] [[package]] name = "crossbeam-utils" version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10", + "lazy_static", ] [[package]] name = "crossbeam-utils" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", + "cfg-if 0.1.10", + "lazy_static", ] [[package]] name = "crypto-mac" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" dependencies = [ - "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array", + "subtle", ] [[package]] name = "ctr" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "022cd691704491df67d25d006fe8eca083098253c4d43516c2206479c58c6736" dependencies = [ - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "stream-cipher 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "block-cipher-trait", + "stream-cipher", ] [[package]] name = "darling" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" dependencies = [ - "darling_core 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", - "darling_macro 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "darling_core", + "darling_macro", ] [[package]] name = "darling_core" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" dependencies = [ - "fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "ident_case 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", ] [[package]] name = "darling_macro" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" dependencies = [ - "darling_core 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "darling_core", + "quote", + "syn", ] [[package]] name = "derivative" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "digest" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" dependencies = [ - "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array", ] +[[package]] +name = "discard" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" + [[package]] name = "dns-sd" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d748509dea20228f63ba519bf142ce2593396386125b01f5b0d6412dab972087" dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "pkg-config", ] [[package]] name = "either" version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "env_logger" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26ecb66b4bdca6c1409b40fb255eefc2bd4f6d135dab3c3124f80ffa2a9661e" dependencies = [ - "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty", + "humantime", + "log", + "termcolor", ] [[package]] name = "error-chain" -version = "0.12.2" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" dependencies = [ - "backtrace 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace", + "version_check", ] [[package]] name = "fake-simd" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" [[package]] name = "fetch_unroll" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d44807d562d137f063cbfe209da1c3f9f2fa8375e11166ef495daab7b847f9" dependencies = [ - "libflate 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "tar 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "ureq 0.11.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libflate", + "tar", + "ureq", ] [[package]] name = "filetime" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8" dependencies = [ - "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "libc", + "redox_syscall 0.2.4", + "winapi 0.3.9", ] [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00" dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "matches", + "percent-encoding 2.1.0", ] [[package]] name = "fuchsia-cprng" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" [[package]] name = "fuchsia-zircon" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "fuchsia-zircon-sys", ] [[package]] name = "fuchsia-zircon-sys" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" + +[[package]] +name = "futures" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7e4c2612746b0df8fed4ce0c69156021b704c9aefa360311c04e6e9e002eed" [[package]] name = "futures" -version = "0.1.29" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9052a1a50244d8d5aa9bf55cbc2fb6f357c86cc52e46c62ed390a7180cf150" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] [[package]] name = "futures-channel" -version = "0.3.5" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2d31b7ec7efab6eefc7c57233bb10b847986139d88cc2f5a02a1ae6871a1846" dependencies = [ - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core", + "futures-sink", ] [[package]] name = "futures-core" -version = "0.3.5" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79e5145dde8da7d1b3892dad07a9c98fc04bc39892b1ecc9692cf53e2b780a65" [[package]] name = "futures-cpupool" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.30", + "num_cpus", ] [[package]] name = "futures-executor" -version = "0.3.5" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9e59fdc009a4b3096bf94f740a0f2424c082521f20a9b08c5c07c48d90fd9b9" dependencies = [ - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core", + "futures-task", + "futures-util", ] +[[package]] +name = "futures-io" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28be053525281ad8259d47e4de5de657b25e7bac113458555bb4b70bc6870500" + [[package]] name = "futures-macro" -version = "0.3.5" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c287d25add322d9f9abdcdc5927ca398917996600182178774032e9f8258fedd" dependencies = [ - "proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "futures-sink" -version = "0.3.5" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf5c69029bda2e743fddd0582d1083951d65cc9539aebf8812f36c3491342d6" [[package]] name = "futures-task" -version = "0.3.5" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13de07eb8ea81ae445aca7b69f5f7bf15d7bf4912d8ca37d6645c77ae8a58d86" dependencies = [ - "once_cell 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "once_cell", ] [[package]] name = "futures-util" -version = "0.3.5" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "632a8cd0f2a4b3fdea1657f08bde063848c3bd00f9bbf6e256b8be78802e624b" dependencies = [ - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-macro 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-project 0.4.22 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-nested 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite 0.2.4", + "pin-utils", + "proc-macro-hack", + "proc-macro-nested", + "slab", ] [[package]] name = "gcc" version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" [[package]] name = "generic-array" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" dependencies = [ - "typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "typenum", ] [[package]] name = "getopts" version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", ] [[package]] name = "getrandom" -version = "0.1.14" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "libc", + "wasi 0.10.1+wasi-snapshot-preview1", ] [[package]] name = "gimli" version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" [[package]] name = "glib" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c685013b7515e668f1b57a165b009d4d28cb139a8a989bbd699c10dad29d0c5" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-executor 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "glib-macros 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "glib-sys 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gobject-sys 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "once_cell 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "futures-util", + "glib-macros", + "glib-sys", + "gobject-sys", + "libc", + "once_cell", ] [[package]] name = "glib-macros" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41486a26d1366a8032b160b59065a59fb528530a46a49f627e7048fb8c064039" dependencies = [ - "anyhow 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-crate 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-error 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "anyhow", + "heck", + "itertools", + "proc-macro-crate", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "glib-sys" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e9b997a66e9a23d073f2b1abb4dbfc3925e0b8952f67efd8d9b6e168e4cdc1" dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "system-deps 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "system-deps", ] [[package]] name = "glob" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "gobject-sys" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "952133b60c318a62bf82ee75b93acc7e84028a093e06b9e27981c2b6fe68218c" dependencies = [ - "glib-sys 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "system-deps 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys", + "libc", + "system-deps", ] [[package]] name = "gstreamer" version = "0.16.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d50f822055923f1cbede233aa5dfd4ee957cf328fb3076e330886094e11d6cf" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "glib 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)", - "glib-sys 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gobject-sys 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "muldiv 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-rational 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "once_cell 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "paste 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "pretty-hex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "cfg-if 1.0.0", + "futures-channel", + "futures-core", + "futures-util", + "glib", + "glib-sys", + "gobject-sys", + "gstreamer-sys", + "libc", + "muldiv", + "num-rational", + "once_cell", + "paste", + "pretty-hex", + "thiserror", ] [[package]] name = "gstreamer-app" version = "0.16.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc80888271338c3ede875d8cafc452eb207476ff5539dcbe0018a8f5b827af0e" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "glib 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)", - "glib-sys 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gobject-sys 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer 0.16.5 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-app-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-base 0.16.5 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "once_cell 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "futures-core", + "futures-sink", + "glib", + "glib-sys", + "gobject-sys", + "gstreamer", + "gstreamer-app-sys", + "gstreamer-base", + "gstreamer-sys", + "libc", + "once_cell", ] [[package]] name = "gstreamer-app-sys" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "813f64275c9e7b33b828b9efcf9dfa64b95996766d4de996e84363ac65b87e3d" dependencies = [ - "glib-sys 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-base-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "system-deps 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys", + "gstreamer-base-sys", + "gstreamer-sys", + "libc", + "system-deps", ] [[package]] name = "gstreamer-base" version = "0.16.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bafd01c56f59cb10f4b5a10f97bb4bdf8c2b2784ae5b04da7e2d400cf6e6afcf" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "glib 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)", - "glib-sys 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gobject-sys 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer 0.16.5 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-base-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "glib", + "glib-sys", + "gobject-sys", + "gstreamer", + "gstreamer-base-sys", + "gstreamer-sys", + "libc", ] [[package]] name = "gstreamer-base-sys" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4b7b6dc2d6e160a1ae28612f602bd500b3fa474ce90bf6bb2f08072682beef5" dependencies = [ - "glib-sys 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gobject-sys 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "system-deps 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys", + "gobject-sys", + "gstreamer-sys", + "libc", + "system-deps", ] [[package]] name = "gstreamer-sys" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1f154082d01af5718c5f8a8eb4f565a4ea5586ad8833a8fc2c2aa6844b601d" dependencies = [ - "glib-sys 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gobject-sys 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "system-deps 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", ] +[[package]] +name = "h2" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462" +dependencies = [ + "byteorder", + "bytes 0.4.12", + "fnv", + "futures 0.1.30", + "http 0.1.21", + "indexmap", + "log", + "slab", + "string", + "tokio-io", +] + +[[package]] +name = "h2" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e4728fd124914ad25e99e3d15a9361a879f6620f63cb56bbb08f95abb97a535" +dependencies = [ + "bytes 0.5.6", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.3", + "indexmap", + "slab", + "tokio 0.2.24", + "tokio-util", + "tracing", + "tracing-futures", +] + +[[package]] +name = "hashbrown" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" + [[package]] name = "heck" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" dependencies = [ - "unicode-segmentation 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-segmentation", ] [[package]] name = "hermit-abi" -version = "0.1.15" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "hex" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" [[package]] name = "hmac" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" dependencies = [ - "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crypto-mac", + "digest", ] [[package]] name = "hostname" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi 0.3.9", +] + +[[package]] +name = "http" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6ccf5ede3a895d8856620237b2f02972c1bbc78d2965ad7fe8838d4a0ed41f0" +dependencies = [ + "bytes 0.4.12", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7245cd7449cc792608c3c8a9eaf69bd4eabbabf802713748fd739c98b82f0747" +dependencies = [ + "bytes 1.0.1", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" +dependencies = [ + "bytes 0.4.12", + "futures 0.1.30", + "http 0.1.21", + "tokio-buf", +] + +[[package]] +name = "http-body" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b" dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "match_cfg 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.5.6", + "http 0.2.3", ] [[package]] name = "httparse" version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" + +[[package]] +name = "httpdate" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47" [[package]] name = "humantime" -version = "2.0.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.11.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "want 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +version = "0.12.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dbe6ed1438e1f8ad955a4701e9a944938e9519f6888d12d8558b645e247d5f6" +dependencies = [ + "bytes 0.4.12", + "futures 0.1.30", + "futures-cpupool", + "h2 0.1.26", + "http 0.1.21", + "http-body 0.1.0", + "httparse", + "iovec", + "itoa", + "log", + "net2", + "rustc_version", + "time 0.1.43", + "tokio 0.1.22", + "tokio-buf", + "tokio-executor", + "tokio-io", + "tokio-reactor", + "tokio-tcp", + "tokio-threadpool", + "tokio-timer", + "want 0.2.0", +] + +[[package]] +name = "hyper" +version = "0.13.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ad767baac13b44d4529fcf58ba2cd0995e36e7b435bc5b039de6f47e880dbf" +dependencies = [ + "bytes 0.5.6", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.2.7", + "http 0.2.3", + "http-body 0.3.1", + "httparse", + "httpdate", + "itoa", + "pin-project 1.0.4", + "socket2", + "tokio 0.2.24", + "tower-service", + "tracing", + "want 0.3.0", ] [[package]] name = "hyper-proxy" -version = "0.4.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cf120ed868e8e0cd22279cc8196c8db126884a5dbb01e0f528018048efd8fee" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.5.6", + "futures 0.3.12", + "http 0.2.3", + "hyper 0.13.9", + "tokio 0.2.24", + "tower-service", + "typed-headers", ] [[package]] name = "ident_case" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "matches", + "unicode-bidi", + "unicode-normalization", ] [[package]] name = "idna" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "matches", + "unicode-bidi", + "unicode-normalization", ] [[package]] name = "if-addrs" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28538916eb3f3976311f5dfbe67b5362d0add1293d0a9cad17debf86f8e3aa48" dependencies = [ - "if-addrs-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "if-addrs-sys", + "libc", + "winapi 0.3.9", ] [[package]] name = "if-addrs-sys" -version = "0.3.1" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de74b9dd780476e837e5eb5ab7c88b49ed304126e412030a0adba99c8efe79ea" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "indexmap" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b" dependencies = [ - "cc 1.0.65 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", + "hashbrown", ] [[package]] name = "instant" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" dependencies = [ - "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", ] [[package]] name = "iovec" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "itertools" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" dependencies = [ - "either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "either", ] [[package]] name = "itoa" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" [[package]] name = "jack" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c1871c91fa65aa328f3bedbaa54a6e5d1de009264684c153eb708ba933aa6f5" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "jack-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "jack-sys", + "lazy_static", + "libc", ] [[package]] name = "jack-sys" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d6ab7ada402b6a27912a2b86504be62a48c58313c886fe72a059127acb4d7" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "libloading 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static", + "libc", + "libloading", ] [[package]] name = "jni" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1981310da491a4f0f815238097d0d43d8072732b5ae5f8bd0d8eadf5bf245402" dependencies = [ - "cesu8 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "combine 3.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "jni-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cesu8", + "combine 3.8.1", + "error-chain", + "jni-sys", + "log", + "walkdir", ] [[package]] name = "jni" version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36bcc950632e48b86da402c5c077590583da5ac0d480103611d5374e7c967a3c" dependencies = [ - "cesu8 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "combine 4.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "jni-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cesu8", + "combine 4.5.2", + "error-chain", + "jni-sys", + "log", + "walkdir", ] [[package]] name = "jni-sys" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "js-sys" version = "0.3.46" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d7383929f7c9c7c2d0fa596f325832df98c3704f2c60553080f7127a58175" dependencies = [ - "wasm-bindgen 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen", ] [[package]] name = "kernel32-sys" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8", + "winapi-build", ] -[[package]] -name = "language-tags" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "lazycell" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "lewton" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d542c1a317036c45c2aa1cf10cc9d403ca91eb2d333ef1a4917e5cb10628bd0" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ogg 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "ogg", + "smallvec 0.6.14", ] [[package]] name = "libc" -version = "0.2.73" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929" [[package]] name = "libflate" -version = "0.1.27" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389de7875e06476365974da3e7ff85d55f1972188ccd9f6020dd7c8156e17914" dependencies = [ - "adler32 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crc32fast 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rle-decode-fast 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "adler32", + "crc32fast", + "libflate_lz77", + "rle-decode-fast", ] [[package]] -name = "libloading" -version = "0.4.3" +name = "libflate_lz77" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "3286f09f7d4926fc486334f28d8d2e6ebe4f7f9994494b6dab27ddfad2c9b11b" [[package]] name = "libloading" -version = "0.5.2" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883" dependencies = [ - "cc 1.0.65 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "winapi 0.3.9", ] [[package]] name = "libmdns" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d8582c174736c53633bc482ac709b24527c018356c3dc6d8e25a788b06b394e" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "hostname 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "if-addrs 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "multimap 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "futures 0.1.30", + "hostname", + "if-addrs", + "log", + "multimap", + "net2", + "quick-error", + "rand 0.7.3", + "tokio-core", ] [[package]] name = "libpulse-binding" -version = "2.19.0" +version = "2.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce89ab17bd343b08bd4321c674ef1477d34f83be18b1ab2ee47a5e5fbee64a91" dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "libpulse-sys 1.15.3 (registry+https://github.com/rust-lang/crates.io-index)", - "num-derive 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "libc", + "libpulse-sys", + "num-derive", + "num-traits", + "winapi 0.3.9", ] [[package]] name = "libpulse-simple-binding" -version = "2.18.1" +version = "2.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e47f6cda2748fb86f15e5e65cc33be306577140f4b500622b5d98df2ca17240" dependencies = [ - "libpulse-binding 2.19.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libpulse-simple-sys 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libpulse-sys 1.15.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libpulse-binding", + "libpulse-simple-sys", + "libpulse-sys", ] [[package]] name = "libpulse-simple-sys" -version = "1.15.1" +version = "1.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "468cf582b7b022c0d1b266fefc7fc8fa7b1ddcb61214224f2f105c95a9c2d5c1" dependencies = [ - "libpulse-sys 1.15.3 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "libpulse-sys", + "pkg-config", ] [[package]] name = "libpulse-sys" -version = "1.15.3" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcfb56118765adba111da47e36278b77d00aebf822e4f014a832fbfa183a13b" dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "num-derive 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "num-derive", + "num-traits", + "pkg-config", + "winapi 0.3.9", ] [[package]] name = "librespot" version = "0.1.3" dependencies = [ - "base64 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)", - "librespot-audio 0.1.3", - "librespot-connect 0.1.3", - "librespot-core 0.1.3", - "librespot-metadata 0.1.3", - "librespot-playback 0.1.3", - "librespot-protocol 0.1.3", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "num-bigint 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rpassword 5.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sha-1 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-process 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-signal 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.13.0", + "env_logger", + "futures 0.1.30", + "getopts", + "hex", + "librespot-audio", + "librespot-connect", + "librespot-core", + "librespot-metadata", + "librespot-playback", + "librespot-protocol", + "log", + "num-bigint", + "protobuf", + "rand 0.7.3", + "rpassword", + "sha-1", + "tokio 0.2.24", + "tokio-io", + "tokio-process", + "tokio-signal", + "url 1.7.2", ] [[package]] name = "librespot-audio" version = "0.1.3" dependencies = [ - "aes-ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bit-set 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "lewton 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)", - "librespot-core 0.1.3", - "librespot-tremor 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "num-bigint 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "vorbis 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "aes-ctr", + "bit-set", + "byteorder", + "bytes 0.4.12", + "futures 0.3.12", + "lewton", + "librespot-core", + "librespot-tremor", + "log", + "num-bigint", + "num-traits", + "tempfile", + "tokio 0.2.24", + "vorbis", ] [[package]] name = "librespot-connect" version = "0.1.3" dependencies = [ - "aes-ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "base64 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "block-modes 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "dns-sd 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libmdns 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "librespot-core 0.1.3", - "librespot-playback 0.1.3", - "librespot-protocol 0.1.3", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "num-bigint 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", - "sha-1 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "aes-ctr", + "base64 0.13.0", + "block-modes", + "dns-sd", + "futures 0.1.30", + "hmac", + "hyper 0.12.35", + "libmdns", + "librespot-core", + "librespot-playback", + "librespot-protocol", + "log", + "num-bigint", + "protobuf", + "rand 0.7.3", + "serde", + "serde_derive", + "serde_json", + "sha-1", + "tokio 0.1.22", + "url 1.7.2", ] [[package]] name = "librespot-core" version = "0.1.3" dependencies = [ - "aes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "base64 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper-proxy 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "librespot-protocol 0.1.3", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "num-bigint 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", - "sha-1 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "shannon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "vergen 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "aes", + "base64 0.13.0", + "byteorder", + "bytes 0.5.6", + "error-chain", + "futures 0.3.12", + "hmac", + "httparse", + "hyper 0.13.9", + "hyper-proxy", + "lazy_static", + "librespot-protocol", + "log", + "num-bigint", + "num-integer", + "num-traits", + "pbkdf2", + "protobuf", + "rand 0.7.3", + "serde", + "serde_derive", + "serde_json", + "sha-1", + "shannon", + "thiserror", + "tokio 0.2.24", + "tokio-util", + "url 1.7.2", + "uuid", + "vergen", ] [[package]] name = "librespot-metadata" version = "0.1.3" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "librespot-core 0.1.3", - "librespot-protocol 0.1.3", - "linear-map 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "futures 0.1.30", + "librespot-core", + "librespot-protocol", + "linear-map", + "log", + "protobuf", ] [[package]] name = "librespot-playback" version = "0.1.3" dependencies = [ - "alsa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cpal 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "glib 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer 0.16.5 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-app 0.16.5 (registry+https://github.com/rust-lang/crates.io-index)", - "jack 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "libpulse-binding 2.19.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libpulse-simple-binding 2.18.1 (registry+https://github.com/rust-lang/crates.io-index)", - "librespot-audio 0.1.3", - "librespot-core 0.1.3", - "librespot-metadata 0.1.3", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "portaudio-rs 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rodio 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sdl2 0.34.3 (registry+https://github.com/rust-lang/crates.io-index)", - "shell-words 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "zerocopy 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "alsa 0.2.2", + "byteorder", + "cpal", + "futures 0.1.30", + "glib", + "gstreamer", + "gstreamer-app", + "jack", + "libc", + "libpulse-binding", + "libpulse-simple-binding", + "librespot-audio", + "librespot-core", + "librespot-metadata", + "log", + "portaudio-rs", + "rodio", + "sdl2", + "shell-words", + "zerocopy", ] [[package]] name = "librespot-protocol" version = "0.1.3" dependencies = [ - "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf-codegen 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf-codegen-pure 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glob", + "protobuf", + "protobuf-codegen", + "protobuf-codegen-pure", ] [[package]] name = "librespot-tremor" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b155a7dc4e4d272e01c37a1b85c1ee1bee7f04980ad4a7784c1a6e0f2de5929b" dependencies = [ - "cc 1.0.65 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (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.18 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "libc", + "ogg-sys", + "pkg-config", ] [[package]] name = "linear-map" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfae20f6b19ad527b550c223fddc3077a547fc70cda94b9b566575423fd303ee" [[package]] name = "lock_api" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" dependencies = [ - "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard", ] [[package]] name = "lock_api" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312" dependencies = [ - "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard", ] [[package]] name = "log" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "log" -version = "0.4.11" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf3805d4480bb5b86070dcfeb9e2cb2ebc148adb753c5cca5f884d1d65a42b2" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10", ] [[package]] name = "mach" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "match_cfg" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" [[package]] name = "matches" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" [[package]] name = "maybe-uninit" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" [[package]] name = "memchr" -version = "2.3.3" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" [[package]] name = "memoffset" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", ] [[package]] name = "mime" version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" [[package]] name = "miniz_oxide" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" dependencies = [ - "adler 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "adler", + "autocfg", ] [[package]] name = "mio" -version = "0.6.22" +version = "0.6.23" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10", + "fuchsia-zircon", + "fuchsia-zircon-sys", + "iovec", + "kernel32-sys", + "libc", + "log", + "miow 0.2.2", + "net2", + "slab", + "winapi 0.2.8", ] [[package]] name = "mio-named-pipes" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656" dependencies = [ - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "log", + "mio", + "miow 0.3.6", + "winapi 0.3.9", ] [[package]] name = "mio-uds" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" dependencies = [ - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec", + "libc", + "mio", ] [[package]] name = "miow" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys", + "net2", + "winapi 0.2.8", + "ws2_32-sys", ] [[package]] name = "miow" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897" dependencies = [ - "socket2 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "socket2", + "winapi 0.3.9", ] [[package]] name = "muldiv" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0419348c027fa7be448d2ae7ea0e4e04c2334c31dc4e74ab29f00a2a7ca69204" [[package]] name = "multimap" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1255076139a83bb467426e7f8d0134968a8118844faa755985e077cf31850333" dependencies = [ - "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "serde", ] [[package]] name = "ndk" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb167c1febed0a496639034d0c76b3b74263636045db5489eee52143c246e73" dependencies = [ - "jni-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ndk-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num_enum 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "jni-sys", + "ndk-sys", + "num_enum", + "thiserror", ] [[package]] name = "ndk-glue" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdf399b8b7a39c6fb153c4ec32c72fd5fe789df24a647f229c239aa7adb15241" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "ndk 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ndk-macro 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ndk-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static", + "libc", + "log", + "ndk", + "ndk-macro", + "ndk-sys", ] [[package]] name = "ndk-macro" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d" dependencies = [ - "darling 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-crate 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "darling", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "ndk-sys" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c44922cb3dbb1c70b5e5f443d63b64363a898564d739ba5198e3a9138442868d" [[package]] name = "net2" -version = "0.2.34" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10", + "libc", + "winapi 0.3.9", ] [[package]] name = "nix" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2c5afeb0198ec7be8569d666644b574345aad2e95a53baf3a532da3e0f3fb32" dependencies = [ - "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 0.9.1", + "cfg-if 0.1.10", + "libc", + "void", ] [[package]] name = "nix" version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.65 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "cc", + "cfg-if 0.1.10", + "libc", + "void", ] [[package]] name = "nom" version = "5.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" dependencies = [ - "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr", + "version_check", ] [[package]] name = "num-bigint" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e9a41747ae4633fce5adffb4d2e81ffc5e89593cb19917f8fb2cc5ff76507bf" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", + "num-integer", + "num-traits", ] [[package]] name = "num-derive" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "num-integer" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", + "num-traits", ] [[package]] name = "num-rational" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", + "num-integer", + "num-traits", ] [[package]] name = "num-traits" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", ] [[package]] name = "num_cpus" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" dependencies = [ - "hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi", + "libc", ] [[package]] name = "num_enum" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca565a7df06f3d4b485494f25ba05da1435950f4dc263440eda7a6fa9b8e36e4" dependencies = [ - "derivative 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num_enum_derive 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "derivative", + "num_enum_derive", ] [[package]] name = "num_enum_derive" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffa5a33ddddfee04c0283a7653987d634e880347e96b5b2ed64de07efb59db9d" dependencies = [ - "proc-macro-crate 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "object" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4" [[package]] name = "oboe" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aadc2b0867bdbb9a81c4d99b9b682958f49dbea1295a81d2f646cca2afdd9fc" dependencies = [ - "jni 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ndk 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ndk-glue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-derive 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "oboe-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jni 0.14.0", + "ndk", + "ndk-glue", + "num-derive", + "num-traits", + "oboe-sys", ] [[package]] name = "oboe-sys" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ff7a51600eabe34e189eec5c995a62f151d8d97e5fbca39e87ca738bb99b82" dependencies = [ - "fetch_unroll 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "fetch_unroll", ] [[package]] name = "ogg" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13e571c3517af9e1729d4c63571a27edd660ade0667973bfc74a67c660c2b651" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", ] [[package]] name = "ogg-sys" version = "0.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a95b8c172e17df1a41bf8d666301d3b2c4efeb90d9d0415e2a4dc0668b35fdb2" dependencies = [ - "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc", + "libc", + "pkg-config", ] [[package]] name = "once_cell" version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" [[package]] name = "opaque-debug" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" [[package]] name = "parking_lot" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" dependencies = [ - "lock_api 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lock_api 0.3.4", + "parking_lot_core 0.6.2", + "rustc_version", ] [[package]] name = "parking_lot" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" dependencies = [ - "instant 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "lock_api 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "instant", + "lock_api 0.4.2", + "parking_lot_core 0.8.2", ] [[package]] name = "parking_lot_core" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10", + "cloudabi", + "libc", + "redox_syscall 0.1.57", + "rustc_version", + "smallvec 0.6.14", + "winapi 0.3.9", ] [[package]] name = "parking_lot_core" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ccb628cad4f84851442432c60ad8e1f607e29752d0bf072cbd0baf28aa34272" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cloudabi 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "instant 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall 0.1.57", + "smallvec 1.6.1", + "winapi 0.3.9", ] [[package]] name = "paste" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5d65c4d95931acda4498f675e332fcbdc9a06705cd07086c510e9b6009cd1c1" [[package]] name = "pbkdf2" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" dependencies = [ - "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.9.3", + "byteorder", + "crypto-mac", + "hmac", + "rand 0.5.6", + "sha2", + "subtle", ] [[package]] name = "peeking_take_while" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "percent-encoding" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" [[package]] name = "percent-encoding" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] name = "pin-project" -version = "0.4.22" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ffbc8e94b38ea3d2d8ba92aea2983b503cd75d0888d75b86bb37970b5698e15" dependencies = [ - "pin-project-internal 0.4.22 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project-internal 0.4.27", +] + +[[package]] +name = "pin-project" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b70b68509f17aa2857863b6fa00bf21fc93674c7a8893de2f469f6aa7ca2f2" +dependencies = [ + "pin-project-internal 1.0.4", +] + +[[package]] +name = "pin-project-internal" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65ad2ae56b6abe3a1ee25f15ee605bacadb9a764edaba9c2bf4103800d4a1895" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] name = "pin-project-internal" -version = "0.4.22" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa25a6393f22ce819b0f50e0be89287292fda8d425be38ee0ca14c4931d9e71" dependencies = [ - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "pin-project-lite" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c917123afa01924fc84bb20c4c03f004d9c38e5127e3c039bbf7f4b9c76a2f6b" + +[[package]] +name = "pin-project-lite" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827" [[package]] name = "pin-utils" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" [[package]] name = "portaudio-rs" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb6b5eff96ccc9bf44d34c379ab03ae944426d83d1694345bdf8159d561d562" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "portaudio-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "libc", + "portaudio-sys", ] [[package]] name = "portaudio-sys" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5194a4fa953b4ffd851c320ef6f0484cd7278cb7169ea9d6c433e49b23f7b7f5" dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "pkg-config", ] [[package]] name = "ppv-lite86" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "pretty-hex" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5c99d529f0d30937f6f4b8a86d988047327bb88d04d2c4afc356de74722131" [[package]] name = "proc-macro-crate" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" dependencies = [ - "toml 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", + "toml", ] [[package]] name = "proc-macro-error" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ - "proc-macro-error-attr 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", ] [[package]] name = "proc-macro-error-attr" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "version_check", ] [[package]] name = "proc-macro-hack" -version = "0.5.16" +version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro-nested" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" [[package]] name = "proc-macro2" -version = "1.0.19" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" dependencies = [ - "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid", ] [[package]] name = "protobuf" version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e86d370532557ae7573551a1ec8235a0f8d6cb276c7c9e6aa490b511c447485" [[package]] name = "protobuf-codegen" version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de113bba758ccf2c1ef816b127c958001b7831136c9bc3f8e9ec695ac4e82b0c" dependencies = [ - "protobuf 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf", ] [[package]] name = "protobuf-codegen-pure" version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d1a4febc73bf0cada1d77c459a0c8e5973179f1cfd5b0f1ab789d45b17b6440" +dependencies = [ + "protobuf", + "protobuf-codegen", +] + +[[package]] +name = "publicsuffix" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bbaa49075179162b49acac1c6aa45fb4dafb5f13cf6794276d77bc7fd95757b" dependencies = [ - "protobuf 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf-codegen 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain", + "idna 0.2.0", + "lazy_static", + "regex", + "url 2.2.0", ] [[package]] name = "qstring" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" dependencies = [ - "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 2.1.0", ] [[package]] name = "quick-error" version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" dependencies = [ - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", ] [[package]] name = "rand" -version = "0.3.23" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "winapi 0.3.9", ] [[package]] name = "rand" -version = "0.4.6" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc 0.2.0", ] [[package]] name = "rand" -version = "0.5.6" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18519b42a40024d661e1714153e9ad0c3de27cd495760ceb09710920f1098b1e" dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "rand_chacha 0.3.0", + "rand_core 0.6.1", + "rand_hc 0.3.0", ] [[package]] -name = "rand" -version = "0.7.3" +name = "rand_chacha" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" dependencies = [ - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86", + "rand_core 0.5.1", ] [[package]] name = "rand_chacha" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" dependencies = [ - "ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86", + "rand_core 0.6.1", ] [[package]] name = "rand_core" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" dependencies = [ - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2", ] [[package]] name = "rand_core" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" [[package]] name = "rand_core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5" +dependencies = [ + "getrandom 0.2.2", ] [[package]] name = "rand_hc" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" dependencies = [ - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1", ] [[package]] -name = "rdrand" -version = "0.4.0" +name = "rand_hc" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.6.1", ] [[package]] name = "redox_syscall" version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" [[package]] -name = "regex" -version = "1.3.9" +name = "redox_syscall" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570" dependencies = [ - "regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", ] [[package]] -name = "regex-syntax" -version = "0.6.18" +name = "regex" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a" +dependencies = [ + "regex-syntax", +] [[package]] -name = "relay" -version = "0.1.1" +name = "regex-syntax" +version = "0.6.22" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581" [[package]] name = "remove_dir_all" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" dependencies = [ - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.9", ] [[package]] name = "ring" -version = "0.16.18" +version = "0.16.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "024a1e66fea74c66c66624ee5622a7ff0e4b73a13b4f5c326ddb50c708944226" dependencies = [ - "cc 1.0.65 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "once_cell 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "web-sys 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi 0.3.9", ] [[package]] name = "rle-decode-fast" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac" [[package]] name = "rodio" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9683532495146e98878d4948fa1a1953f584cd923f2a5f5c26b7a8701b56943" dependencies = [ - "cpal 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cpal", ] [[package]] name = "rpassword" -version = "5.0.0" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc936cf8a7ea60c58f030fd36a612a48f440610214dc54bc36431f9ea0c3efb" dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "winapi 0.3.9", ] [[package]] name = "rustc-demangle" version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232" [[package]] name = "rustc-hash" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc_version" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "semver", ] [[package]] name = "rustls" -version = "0.16.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "064fd21ff87c6e87ed4506e68beb42459caa4a0e2eb144932e6776768556980b" dependencies = [ - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.16.18 (registry+https://github.com/rust-lang/crates.io-index)", - "sct 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki 0.21.3 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.13.0", + "log", + "ring", + "sct", + "webpki", ] [[package]] name = "ryu" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "safemem" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" [[package]] name = "same-file" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" dependencies = [ - "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util", ] [[package]] name = "scoped-tls" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28" [[package]] name = "scopeguard" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "sct" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3042af939fca8c3453b7af0f1c66e533a15a86169e39de2657310ade8f98d3c" dependencies = [ - "ring 0.16.18 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ring", + "untrusted", ] [[package]] name = "sdl2" version = "0.34.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcbb85f4211627a7291c83434d6bbfa723e28dcaa53c7606087e3c61929e4b9c" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "sdl2-sys 0.34.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "lazy_static", + "libc", + "sdl2-sys", ] [[package]] name = "sdl2-sys" version = "0.34.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d81feded049b9c14eceb4a4f6d596a98cebbd59abdba949c5552a015466d33" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "version-compare 0.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10", + "libc", + "version-compare", ] [[package]] name = "semver" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "semver-parser", ] [[package]] name = "semver-parser" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.114" +version = "1.0.122" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "974ef1bd2ad8a507599b336595454081ff68a9599b4890af7643c0c0ed73a62c" +dependencies = [ + "serde_derive", +] [[package]] name = "serde_derive" -version = "1.0.114" +version = "1.0.122" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dee1f300f838c8ac340ecb0112b3ac472464fa67e87292bdb3dfc9c49128e17" dependencies = [ - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "serde_json" -version = "1.0.56" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a" dependencies = [ - "itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa", + "ryu", + "serde", ] [[package]] name = "sha-1" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" dependencies = [ - "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "block-buffer", + "digest", + "fake-simd", + "opaque-debug", ] +[[package]] +name = "sha1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" + [[package]] name = "sha2" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" dependencies = [ - "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "block-buffer", + "digest", + "fake-simd", + "opaque-debug", ] [[package]] name = "shannon" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ea5b41c9427b56caa7b808cb548a04fb50bb5b9e98590b53f28064ff4174561" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", ] [[package]] name = "shell-words" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fa3938c99da4914afedd13bf3d79bcb6c277d1b2c398d23257a304d9e1b074" [[package]] name = "shlex" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" [[package]] name = "signal-hook-registry" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6" dependencies = [ - "arc-swap 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] -[[package]] -name = "slab" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "slab" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" [[package]] name = "smallvec" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "smallvec" -version = "0.6.13" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0" dependencies = [ - "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "maybe-uninit", ] [[package]] name = "smallvec" -version = "1.5.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "socket2" -version = "0.3.12" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "libc", + "winapi 0.3.9", ] [[package]] name = "spin" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "standback" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66a8cff4fa24853fdf6b51f75c6d7f8206d7c75cab4e467bcd7f25c2b1febe0" +dependencies = [ + "version_check", +] [[package]] name = "stdweb" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e" + +[[package]] +name = "stdweb" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" +dependencies = [ + "discard", + "rustc_version", + "stdweb-derive", + "stdweb-internal-macros", + "stdweb-internal-runtime", + "wasm-bindgen", +] + +[[package]] +name = "stdweb-derive" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "serde_derive", + "syn", +] + +[[package]] +name = "stdweb-internal-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" +dependencies = [ + "base-x", + "proc-macro2", + "quote", + "serde", + "serde_derive", + "serde_json", + "sha1", + "syn", +] + +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" [[package]] name = "stream-cipher" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8131256a5896cabcf5eb04f4d6dacbe1aefda854b0d9896e09cb58829ec5638c" +dependencies = [ + "generic-array", +] + +[[package]] +name = "string" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" dependencies = [ - "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12", ] [[package]] name = "strsim" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" [[package]] name = "strum" version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b" [[package]] name = "strum_macros" version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c" dependencies = [ - "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "heck", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "subtle" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" [[package]] name = "syn" -version = "1.0.35" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" dependencies = [ - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "unicode-xid", ] [[package]] name = "synstructure" version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" dependencies = [ - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", + "unicode-xid", ] [[package]] name = "system-deps" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3ecc17269a19353b3558b313bba738b25d82993e30d62a18406a24aba4649b" dependencies = [ - "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "strum 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", - "strum_macros 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", - "version-compare 0.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "heck", + "pkg-config", + "strum", + "strum_macros", + "thiserror", + "toml", + "version-compare", ] -[[package]] -name = "take" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "take_mut" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "tar" -version = "0.4.30" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69b4283cf44997cad75fd635aa70e16f3317248c4c8dfd96ad134d15d4d34db" dependencies = [ - "filetime 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", - "xattr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime", + "libc", + "xattr", ] [[package]] name = "tempfile" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "libc", + "rand 0.8.2", + "redox_syscall 0.2.4", + "remove_dir_all", + "winapi 0.3.9", ] [[package]] name = "termcolor" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" dependencies = [ - "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util", ] [[package]] name = "thiserror" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76cc616c6abf8c8928e2fdcc0dbfab37175edd8fb49a4641066ad1364fdab146" dependencies = [ - "thiserror-impl 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1" dependencies = [ - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "time" version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +dependencies = [ + "libc", + "winapi 0.3.9", +] + +[[package]] +name = "time" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1195b046942c221454c2539395f85413b33383a067449d78aab2b7b052a142f7" dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "const_fn", + "libc", + "standback", + "stdweb 0.4.20", + "time-macros", + "version_check", + "winapi 0.3.9", +] + +[[package]] +name = "time-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" +dependencies = [ + "proc-macro-hack", + "time-macros-impl", +] + +[[package]] +name = "time-macros-impl" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5c3be1edfad6027c69f5491cf4cb310d1a71ecd6af742788c6ff8bced86b8fa" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "standback", + "syn", ] [[package]] name = "tinyvec" -version = "0.3.3" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf8dbc19eb42fba10e8feaaec282fb50e2c14b2726d6301dbfeed0f73306a6f" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-current-thread 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-fs 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-sync 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-udp 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-uds 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12", + "futures 0.1.30", + "mio", + "num_cpus", + "tokio-codec", + "tokio-current-thread", + "tokio-executor", + "tokio-fs", + "tokio-io", + "tokio-reactor", + "tokio-sync", + "tokio-tcp", + "tokio-threadpool", + "tokio-timer", + "tokio-udp", + "tokio-uds", +] + +[[package]] +name = "tokio" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099837d3464c16a808060bb3f02263b412f6fafcb5d01c533d309985fbeebe48" +dependencies = [ + "bytes 0.5.6", + "fnv", + "futures-core", + "iovec", + "lazy_static", + "libc", + "memchr", + "mio", + "mio-named-pipes", + "mio-uds", + "num_cpus", + "pin-project-lite 0.1.11", + "signal-hook-registry", + "slab", + "tokio-macros", + "winapi 0.3.9", +] + +[[package]] +name = "tokio-buf" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46" +dependencies = [ + "bytes 0.4.12", + "either", + "futures 0.1.30", ] [[package]] name = "tokio-codec" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b2998660ba0e70d18684de5d06b70b70a3a747469af9dea7618cc59e75976b" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12", + "futures 0.1.30", + "tokio-io", ] [[package]] name = "tokio-core" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87b1395334443abca552f63d4f61d0486f12377c2ba8b368e523f89e828cffd4" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)", - "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12", + "futures 0.1.30", + "iovec", + "log", + "mio", + "scoped-tls", + "tokio 0.1.22", + "tokio-executor", + "tokio-io", + "tokio-reactor", + "tokio-timer", ] [[package]] name = "tokio-current-thread" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1de0e32a83f131e002238d7ccde18211c0a5397f60cbfffcb112868c2e0e20e" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.30", + "tokio-executor", ] [[package]] name = "tokio-executor" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb2d1b8f4548dbf5e1f7818512e9c406860678f29c300cdf0ebac72d1a3a1671" dependencies = [ - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.2", + "futures 0.1.30", ] [[package]] name = "tokio-fs" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "297a1206e0ca6302a0eed35b700d292b275256f596e2f3fea7729d5e629b6ff4" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.30", + "tokio-io", + "tokio-threadpool", ] [[package]] name = "tokio-io" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12", + "futures 0.1.30", + "log", ] [[package]] -name = "tokio-process" -version = "0.2.5" +name = "tokio-macros" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e44da00bfc73a25f814cd8d7e57a68a5c31b74b3152a0a1d1f590c97ed06265a" dependencies = [ - "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)", - "mio-named-pipes 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-signal 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "tokio-proto" -version = "0.1.1" +name = "tokio-process" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "382d90f43fa31caebe5d3bc6cfd854963394fff3b8cb59d5146607aaae7e7e43" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-queue 0.1.2", + "futures 0.1.30", + "lazy_static", + "libc", + "log", + "mio", + "mio-named-pipes", + "tokio-io", + "tokio-reactor", + "tokio-signal", + "winapi 0.3.9", ] [[package]] name = "tokio-reactor" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09bc590ec4ba8ba87652da2068d150dcada2cfa2e07faae270a5e0409aa51351" dependencies = [ - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-sync 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-service" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.2", + "futures 0.1.30", + "lazy_static", + "log", + "mio", + "num_cpus", + "parking_lot 0.9.0", + "slab", + "tokio-executor", + "tokio-io", + "tokio-sync", ] [[package]] name = "tokio-signal" version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0c34c6e548f101053321cba3da7cbb87a610b85555884c41b07da2eb91aff12" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)", - "mio-uds 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.30", + "libc", + "mio", + "mio-uds", + "signal-hook-registry", + "tokio-executor", + "tokio-io", + "tokio-reactor", + "winapi 0.3.9", ] [[package]] name = "tokio-sync" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edfe50152bc8164fcc456dab7891fa9bf8beaf01c5ee7e1dd43a397c3cf87dee" dependencies = [ - "fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv", + "futures 0.1.30", ] [[package]] name = "tokio-tcp" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98df18ed66e3b72e742f185882a9e201892407957e45fbff8da17ae7a7c51f72" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12", + "futures 0.1.30", + "iovec", + "mio", + "tokio-io", + "tokio-reactor", ] [[package]] name = "tokio-threadpool" version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df720b6581784c118f0eb4310796b12b1d242a7eb95f716a8367855325c25f89" dependencies = [ - "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-queue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque", + "crossbeam-queue 0.2.3", + "crossbeam-utils 0.7.2", + "futures 0.1.30", + "lazy_static", + "log", + "num_cpus", + "slab", + "tokio-executor", ] [[package]] name = "tokio-timer" version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93044f2d313c95ff1cb7809ce9a7a05735b012288a888b62d4434fd58c94f296" dependencies = [ - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.2", + "futures 0.1.30", + "slab", + "tokio-executor", ] [[package]] name = "tokio-udp" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2a0b10e610b39c38b031a2fcab08e4b82f16ece36504988dcbd81dbba650d82" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12", + "futures 0.1.30", + "log", + "mio", + "tokio-codec", + "tokio-io", + "tokio-reactor", ] [[package]] name = "tokio-uds" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab57a4ac4111c8c9dbcf70779f6fc8bc35ae4b2454809febac840ad19bd7e4e0" +dependencies = [ + "bytes 0.4.12", + "futures 0.1.30", + "iovec", + "libc", + "log", + "mio", + "mio-uds", + "tokio-codec", + "tokio-io", + "tokio-reactor", +] + +[[package]] +name = "tokio-util" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)", - "mio-uds 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.5.6", + "futures-core", + "futures-io", + "futures-sink", + "log", + "pin-project-lite 0.1.11", + "tokio 0.2.24", ] [[package]] name = "toml" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" dependencies = [ - "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "serde", ] [[package]] -name = "try-lock" -version = "0.1.0" +name = "tower-service" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] -name = "typenum" -version = "1.12.0" +name = "tracing" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f47026cdc4080c07e49b37087de021820269d996f581aac150ef9e5583eefe3" +dependencies = [ + "cfg-if 1.0.0", + "log", + "pin-project-lite 0.2.4", + "tracing-core", +] [[package]] -name = "unicase" -version = "2.6.0" +name = "tracing-core" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "tracing-futures" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab7bb6f14721aa00656086e9335d363c5c8747bae02ebe32ea2c7dece5689b4c" +dependencies = [ + "pin-project 0.4.27", + "tracing", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + +[[package]] +name = "typed-headers" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3179a61e9eccceead5f1574fd173cf2e162ac42638b9bf214c6ad0baf7efa24a" dependencies = [ - "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.11.0", + "bytes 0.5.6", + "chrono", + "http 0.2.3", + "mime", ] +[[package]] +name = "typenum" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" + [[package]] name = "unicode-bidi" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "matches", ] [[package]] name = "unicode-normalization" -version = "0.1.13" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13e63ab62dbe32aeee58d1c5408d35c36c392bba5d9d3142287219721afe606" dependencies = [ - "tinyvec 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tinyvec", ] [[package]] name = "unicode-segmentation" version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" [[package]] name = "unicode-width" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" [[package]] name = "unicode-xid" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" [[package]] name = "unreachable" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" dependencies = [ - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "void", ] [[package]] name = "untrusted" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "ureq" -version = "0.11.4" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "294b85ef5dbc3670a72e82a89971608a1fcc4ed5c7c5a2895230d31a95f0569b" dependencies = [ - "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "chunked_transfer 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "qstring 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustls 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", - "url 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki 0.21.3 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki-roots 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.13.0", + "chunked_transfer", + "cookie", + "cookie_store", + "log", + "once_cell", + "qstring", + "rustls", + "url 2.2.0", + "webpki", + "webpki-roots", ] [[package]] name = "url" version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" dependencies = [ - "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "idna 0.1.5", + "matches", + "percent-encoding 1.0.1", ] [[package]] name = "url" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5909f2b0817350449ed73e8bcd81c8c3c8d9a7a5d8acba4b27db277f1868976e" dependencies = [ - "form_urlencoded 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "form_urlencoded", + "idna 0.2.0", + "matches", + "percent-encoding 2.1.0", ] [[package]] name = "uuid" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.2.2", ] [[package]] name = "vergen" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ce50d8996df1f85af15f2cd8d33daae6e479575123ef4314a51a70a230739cb" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "chrono 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "chrono", ] [[package]] name = "version-compare" version = "0.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1" [[package]] name = "version_check" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" [[package]] name = "void" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" [[package]] name = "vorbis" version = "0.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e8a194457075360557b82dac78f7ca2d65bbb6679bccfabae5f7c8c706cc776" dependencies = [ - "libc 0.2.73 (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.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "vorbisfile-sys 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "ogg-sys", + "vorbis-sys", + "vorbisfile-sys", ] [[package]] name = "vorbis-sys" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9ed6ef5361a85e68ccc005961d995c2d44e31f0816f142025f2ca2383dfbfd" dependencies = [ - "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (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.18 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "libc", + "ogg-sys", + "pkg-config", ] [[package]] name = "vorbisfile-sys" version = "0.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f4306d7e1ac4699b55e20de9483750b90c250913188efd7484db6bfbe9042d1" dependencies = [ - "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (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.18 (registry+https://github.com/rust-lang/crates.io-index)", - "vorbis-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc", + "libc", + "ogg-sys", + "pkg-config", + "vorbis-sys", ] [[package]] name = "walkdir" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" +dependencies = [ + "same-file", + "winapi 0.3.9", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230" dependencies = [ - "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.30", + "log", + "try-lock", ] [[package]] name = "want" -version = "0.0.4" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "try-lock 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log", + "try-lock", ] [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.10.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93c6c3420963c5c64bca373b25e77acb562081b9bb4dd5bb864187742186cea9" [[package]] name = "wasm-bindgen" version = "0.2.69" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cd364751395ca0f68cafb17666eee36b63077fb5ecd972bbcd74c90c4bf736e" dependencies = [ - "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-macro 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.69" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1114f89ab1f4106e5b55e688b828c0ab0ea593a1ea7c094b141b14cbaaec2d62" dependencies = [ - "bumpalo 3.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-shared 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.69" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6ac8995ead1f084a8dea1e65f194d0973800c7f571f6edd70adf06ecf77084" dependencies = [ - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-macro-support 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "quote", + "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.69" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a48c72f299d80557c7c62e37e7225369ecc0c963964059509fbafe917c7549" dependencies = [ - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-backend 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-shared 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.69" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e7811dd7f9398f14cc76efd356f98f03aa30419dea46aa810d71e819fc97158" [[package]] name = "web-sys" version = "0.3.46" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222b1ef9334f92a21d3fb53dc3fd80f30836959a90f9274a626d7e06315ba3c3" dependencies = [ - "js-sys 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys", + "wasm-bindgen", ] [[package]] name = "webpki" -version = "0.21.3" +version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" dependencies = [ - "ring 0.16.18 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ring", + "untrusted", ] [[package]] name = "webpki-roots" -version = "0.18.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82015b7e0b8bad8185994674a13a93306bea76cf5a16c5a181382fd3a5ec2376" dependencies = [ - "webpki 0.21.3 (registry+https://github.com/rust-lang/crates.io-index)", + "webpki", ] [[package]] name = "winapi" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-build" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.9", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "ws2_32-sys" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8", + "winapi-build", ] [[package]] name = "xattr" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "zerocopy" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6580539ad917b7c026220c4b3f2c08d52ce54d6ce0dc491e66002e35388fab46" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "zerocopy-derive 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "zerocopy-derive", ] [[package]] name = "zerocopy-derive" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d498dbd1fd7beb83c86709ae1c33ca50942889473473d287d56ce4770a18edfb" dependencies = [ - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[metadata] -"checksum addr2line 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c0929d69e78dd9bf5408269919fcbcaeb2e35e5d43e5815517cdc6a8e11a423" -"checksum adler 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" -"checksum adler32 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" -"checksum aes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "54eb1d8fe354e5fc611daf4f2ea97dd45a765f4f1e4512306ec183ae2e8f20c9" -"checksum aes-ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2e5b0458ea3beae0d1d8c0f3946564f8e10f90646cf78c06b4351052058d1ee" -"checksum aes-soft 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cfd7e7ae3f9a1fb5c03b389fc6bb9a51400d0c13053f0dca698c832bfd893a0d" -"checksum aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100" -"checksum alsa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b4a0d4ebc8b23041c5de9bc9aee13b4bad844a589479701f31a5934cfe4aeb32" -"checksum alsa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "eb213f6b3e4b1480a60931ca2035794aa67b73103d254715b1db7b70dcb3c934" -"checksum alsa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b0edcbbf9ef68f15ae1b620f722180b82a98b6f0628d30baa6b8d2a5abc87d58" -"checksum alsa-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d5a0559bcd3f7a482690d98be41c08a43e92f669b179433e95ddf5e8b8fd36a3" -"checksum anyhow 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "2c0df63cb2955042487fad3aefd2c6e3ae7389ac5dc1beb28921de0b69f779d4" -"checksum arc-swap 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034" -"checksum ascii 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" -"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" -"checksum backtrace 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "ef5140344c85b01f9bbb4d4b7288a8aa4b3287ccef913a14bcc78a1063623598" -"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" -"checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" -"checksum base64 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" -"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" -"checksum bindgen 0.53.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c72a978d268b1d70b0e963217e60fdabd9523a941457a6c42a7315d15c7e89e5" -"checksum bit-set 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de" -"checksum bit-vec 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5f0dc55f2d8a1a85650ac47858bb001b4c0dd73d79e3c455a842925e68d29cd3" -"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" -"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -"checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774" -"checksum block-modes 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "31aa8410095e39fdb732909fb5730a48d5bd7c2e3cd76bd1b07b3dbea130c529" -"checksum block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" -"checksum bumpalo 3.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" -"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" -"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" -"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" -"checksum bytes 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" -"checksum cc 1.0.65 (registry+https://github.com/rust-lang/crates.io-index)" = "95752358c8f7552394baf48cd82695b345628ad3f170d607de3ca03b8dacca15" -"checksum cesu8 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" -"checksum cexpr 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" -"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -"checksum chrono 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "c74d84029116787153e02106bf53e66828452a4b325cc8652b788b5967c0a0b6" -"checksum chunked_transfer 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7477065d45a8fe57167bf3cf8bcd3729b54cfcb81cca49bda2d038ea89ae82ca" -"checksum clang-sys 0.29.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fe6837df1d5cba2397b835c8530f51723267e16abbf83892e9e5af4f0e5dd10a" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum cloudabi 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467" -"checksum combine 3.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" -"checksum combine 4.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b9417a0c314565e2abffaece67e95a8cb51f9238cd39f3764d9dfdf09e72b20c" -"checksum cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5" -"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" -"checksum coreaudio-rs 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f229761965dad3e9b11081668a6ea00f1def7aa46062321b5ec245b834f6e491" -"checksum coreaudio-sys 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d6570ee6e089131e928d5ec9236db9e818aa3cf850f48b0eec6ef700571271d4" -"checksum cpal 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05631e2089dfa5d3b6ea1cfbbfd092e2ee5deeb69698911bc976b28b746d3657" -"checksum crc32fast 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" -"checksum crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" -"checksum crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" -"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" -"checksum crossbeam-queue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" -"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" -"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" -"checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" -"checksum ctr 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "022cd691704491df67d25d006fe8eca083098253c4d43516c2206479c58c6736" -"checksum darling 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" -"checksum darling_core 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" -"checksum darling_macro 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" -"checksum derivative 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cb582b60359da160a9477ee80f15c8d784c477e69c217ef2cdd4169c24ea380f" -"checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -"checksum dns-sd 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d748509dea20228f63ba519bf142ce2593396386125b01f5b0d6412dab972087" -"checksum either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" -"checksum env_logger 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f26ecb66b4bdca6c1409b40fb255eefc2bd4f6d135dab3c3124f80ffa2a9661e" -"checksum error-chain 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d371106cc88ffdfb1eabd7111e432da544f16f3e2d7bf1dfe8bf575f1df045cd" -"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" -"checksum fetch_unroll 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b5c55005e95bbe15f5f72a73b6597d0dc82ddc97ffe2ca097a99dcd591fefbca" -"checksum filetime 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "0c122a393ea57648015bf06fbd3d372378992e86b9ff5a7a497b076a28c79efe" -"checksum fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -"checksum form_urlencoded 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef" -"checksum futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f366ad74c28cca6ba456d95e6422883cfb4b252a83bed929c83abfdbbf2967d5" -"checksum futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399" -"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" -"checksum futures-executor 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "10d6bb888be1153d3abeb9006b11b02cf5e9b209fda28693c31ae1e4e012e314" -"checksum futures-macro 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39" -"checksum futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f2032893cb734c7a05d85ce0cc8b8c4075278e93b24b66f9de99d6eb0fa8acc" -"checksum futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626" -"checksum futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6" -"checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" -"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" -"checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" -"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" -"checksum gimli 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" -"checksum glib 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0c685013b7515e668f1b57a165b009d4d28cb139a8a989bbd699c10dad29d0c5" -"checksum glib-macros 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "41486a26d1366a8032b160b59065a59fb528530a46a49f627e7048fb8c064039" -"checksum glib-sys 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7e9b997a66e9a23d073f2b1abb4dbfc3925e0b8952f67efd8d9b6e168e4cdc1" -"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" -"checksum gobject-sys 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "952133b60c318a62bf82ee75b93acc7e84028a093e06b9e27981c2b6fe68218c" -"checksum gstreamer 0.16.5 (registry+https://github.com/rust-lang/crates.io-index)" = "5d50f822055923f1cbede233aa5dfd4ee957cf328fb3076e330886094e11d6cf" -"checksum gstreamer-app 0.16.5 (registry+https://github.com/rust-lang/crates.io-index)" = "cc80888271338c3ede875d8cafc452eb207476ff5539dcbe0018a8f5b827af0e" -"checksum gstreamer-app-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "813f64275c9e7b33b828b9efcf9dfa64b95996766d4de996e84363ac65b87e3d" -"checksum gstreamer-base 0.16.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bafd01c56f59cb10f4b5a10f97bb4bdf8c2b2784ae5b04da7e2d400cf6e6afcf" -"checksum gstreamer-base-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a4b7b6dc2d6e160a1ae28612f602bd500b3fa474ce90bf6bb2f08072682beef5" -"checksum gstreamer-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fc1f154082d01af5718c5f8a8eb4f565a4ea5586ad8833a8fc2c2aa6844b601d" -"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" -"checksum hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" -"checksum hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" -"checksum hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" -"checksum hostname 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" -"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" -"checksum humantime 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3c1ad908cc71012b7bea4d0c53ba96a8cba9962f048fa68d143376143d863b7a" -"checksum hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)" = "34a590ca09d341e94cddf8e5af0bbccde205d5fbc2fa3c09dd67c7f85cea59d7" -"checksum hyper-proxy 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44f0925de2747e481e6e477dd212c25e8f745567f02f6182e04d27b97c3fbece" -"checksum ident_case 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" -"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" -"checksum if-addrs 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f12906406f12abf5569643c46b29aec78313dc1537b17dd5c5250169790c4db9" -"checksum if-addrs-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e2556f16544202bcfe0aa5d20a01a6b815f736b136b3ad76dc547ee6b5bb1df" -"checksum instant 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" -"checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" -"checksum itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" -"checksum itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" -"checksum jack 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7c1871c91fa65aa328f3bedbaa54a6e5d1de009264684c153eb708ba933aa6f5" -"checksum jack-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0d4ca501477fd3cd93a36df581046e5d6338ed826cf7e9b8d302603521e6cc3" -"checksum jni 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1981310da491a4f0f815238097d0d43d8072732b5ae5f8bd0d8eadf5bf245402" -"checksum jni 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "36bcc950632e48b86da402c5c077590583da5ac0d480103611d5374e7c967a3c" -"checksum jni-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" -"checksum js-sys 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d7383929f7c9c7c2d0fa596f325832df98c3704f2c60553080f7127a58175" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" -"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" -"checksum lewton 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8d542c1a317036c45c2aa1cf10cc9d403ca91eb2d333ef1a4917e5cb10628bd0" -"checksum libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)" = "bd7d4bd64732af4bf3a67f367c27df8520ad7e230c5817b8ff485864d80242b9" -"checksum libflate 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)" = "d9135df43b1f5d0e333385cb6e7897ecd1a43d7d11b91ac003f4d2c2d2401fdd" -"checksum libloading 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fd38073de8f7965d0c17d30546d4bb6da311ab428d1c7a3fc71dff7f9d4979b9" -"checksum libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" -"checksum libmdns 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5d8582c174736c53633bc482ac709b24527c018356c3dc6d8e25a788b06b394e" -"checksum libpulse-binding 2.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1e8f85a42300c868de4849bb72eda5a65cea08c3ca61396b72c2d7c28a87f055" -"checksum libpulse-simple-binding 2.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a047f4502997eed57b3e9d8e71f2b860da91a20bb7e15c65d1f183a7b4fb1226" -"checksum libpulse-simple-sys 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9b72cb239bc4de6858fa0bbad27419e72cd4466f079ca56f21d94b0a712ab02e" -"checksum libpulse-sys 1.15.3 (registry+https://github.com/rust-lang/crates.io-index)" = "706e95c4b87ebb81c1e7763c74bf7d5ba897208f1a8aa5fc7bea8298dee8f2ca" -"checksum librespot-tremor 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b155a7dc4e4d272e01c37a1b85c1ee1bee7f04980ad4a7784c1a6e0f2de5929b" -"checksum linear-map 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bfae20f6b19ad527b550c223fddc3077a547fc70cda94b9b566575423fd303ee" -"checksum lock_api 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" -"checksum lock_api 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312" -"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" -"checksum log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" -"checksum mach 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" -"checksum match_cfg 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" -"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" -"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" -"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" -"checksum memoffset 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c198b026e1bbf08a937e94c6c60f9ec4a2267f5b0d2eec9c1b21b061ce2be55f" -"checksum mime 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" -"checksum miniz_oxide 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" -"checksum mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)" = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430" -"checksum mio-named-pipes 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656" -"checksum mio-uds 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" -"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum miow 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "07b88fb9795d4d36d62a012dfbf49a8f5cf12751f36d31a9dbe66d528e58979e" -"checksum muldiv 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0419348c027fa7be448d2ae7ea0e4e04c2334c31dc4e74ab29f00a2a7ca69204" -"checksum multimap 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d8883adfde9756c1d30b0f519c9b8c502a94b41ac62f696453c37c7fc0a958ce" -"checksum ndk 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5eb167c1febed0a496639034d0c76b3b74263636045db5489eee52143c246e73" -"checksum ndk-glue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdf399b8b7a39c6fb153c4ec32c72fd5fe789df24a647f229c239aa7adb15241" -"checksum ndk-macro 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d" -"checksum ndk-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c44922cb3dbb1c70b5e5f443d63b64363a898564d739ba5198e3a9138442868d" -"checksum net2 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)" = "2ba7c918ac76704fb42afcbbb43891e72731f3dcca3bef2a19786297baf14af7" -"checksum nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229" -"checksum nix 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a2c5afeb0198ec7be8569d666644b574345aad2e95a53baf3a532da3e0f3fb32" -"checksum nom 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" -"checksum num-bigint 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e9a41747ae4633fce5adffb4d2e81ffc5e89593cb19917f8fb2cc5ff76507bf" -"checksum num-derive 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" -"checksum num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b" -"checksum num-rational 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" -"checksum num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" -"checksum num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" -"checksum num_enum 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca565a7df06f3d4b485494f25ba05da1435950f4dc263440eda7a6fa9b8e36e4" -"checksum num_enum_derive 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ffa5a33ddddfee04c0283a7653987d634e880347e96b5b2ed64de07efb59db9d" -"checksum object 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" -"checksum oboe 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1aadc2b0867bdbb9a81c4d99b9b682958f49dbea1295a81d2f646cca2afdd9fc" -"checksum oboe-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "68ff7a51600eabe34e189eec5c995a62f151d8d97e5fbca39e87ca738bb99b82" -"checksum ogg 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d79f1db9148be9d0e174bb3ac890f6030fcb1ed947267c5a91ee4c91b5a91e15" -"checksum ogg-sys 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "a95b8c172e17df1a41bf8d666301d3b2c4efeb90d9d0415e2a4dc0668b35fdb2" -"checksum once_cell 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" -"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" -"checksum parking_lot 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" -"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" -"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" -"checksum parking_lot_core 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b" -"checksum paste 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c5d65c4d95931acda4498f675e332fcbdc9a06705cd07086c510e9b6009cd1c1" -"checksum pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" -"checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" -"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" -"checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" -"checksum pin-project 0.4.22 (registry+https://github.com/rust-lang/crates.io-index)" = "12e3a6cdbfe94a5e4572812a0201f8c0ed98c1c452c7b8563ce2276988ef9c17" -"checksum pin-project-internal 0.4.22 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0ffd45cf79d88737d7cc85bfd5d2894bee1139b356e616fe85dc389c61aaf7" -"checksum pin-project-lite 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c917123afa01924fc84bb20c4c03f004d9c38e5127e3c039bbf7f4b9c76a2f6b" -"checksum pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -"checksum pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "d36492546b6af1463394d46f0c834346f31548646f6ba10849802c9c9a27ac33" -"checksum portaudio-rs 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cdb6b5eff96ccc9bf44d34c379ab03ae944426d83d1694345bdf8159d561d562" -"checksum portaudio-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5194a4fa953b4ffd851c320ef6f0484cd7278cb7169ea9d6c433e49b23f7b7f5" -"checksum ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" -"checksum pretty-hex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5c99d529f0d30937f6f4b8a86d988047327bb88d04d2c4afc356de74722131" -"checksum proc-macro-crate 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" -"checksum proc-macro-error 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -"checksum proc-macro-error-attr 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -"checksum proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)" = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4" -"checksum proc-macro-nested 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" -"checksum proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12" -"checksum protobuf 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8e86d370532557ae7573551a1ec8235a0f8d6cb276c7c9e6aa490b511c447485" -"checksum protobuf-codegen 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de113bba758ccf2c1ef816b127c958001b7831136c9bc3f8e9ec695ac4e82b0c" -"checksum protobuf-codegen-pure 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d1a4febc73bf0cada1d77c459a0c8e5973179f1cfd5b0f1ab789d45b17b6440" -"checksum qstring 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" -"checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" -"checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" -"checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" -"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" -"checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" -"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -"checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" -"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)" = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" -"checksum regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" -"checksum regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)" = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" -"checksum relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1576e382688d7e9deecea24417e350d3062d97e32e45d70b1cde65994ff1489a" -"checksum remove_dir_all 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -"checksum ring 0.16.18 (registry+https://github.com/rust-lang/crates.io-index)" = "70017ed5c555d79ee3538fc63ca09c70ad8f317dcadc1adc2c496b60c22bb24f" -"checksum rle-decode-fast 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac" -"checksum rodio 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c9683532495146e98878d4948fa1a1953f584cd923f2a5f5c26b7a8701b56943" -"checksum rpassword 5.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d755237fc0f99d98641540e66abac8bc46a0652f19148ac9e21de2da06b326c9" -"checksum rustc-demangle 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232" -"checksum rustc-hash 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum rustls 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b25a18b1bf7387f0145e7f8324e700805aade3842dd3db2e74e4cdeb4677c09e" -"checksum ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" -"checksum safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" -"checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -"checksum scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28" -"checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -"checksum sct 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e3042af939fca8c3453b7af0f1c66e533a15a86169e39de2657310ade8f98d3c" -"checksum sdl2 0.34.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fcbb85f4211627a7291c83434d6bbfa723e28dcaa53c7606087e3c61929e4b9c" -"checksum sdl2-sys 0.34.3 (registry+https://github.com/rust-lang/crates.io-index)" = "28d81feded049b9c14eceb4a4f6d596a98cebbd59abdba949c5552a015466d33" -"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)" = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3" -"checksum serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)" = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e" -"checksum serde_json 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)" = "3433e879a558dde8b5e8feb2a04899cf34fdde1fafb894687e52105fc1162ac3" -"checksum sha-1 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" -"checksum sha2 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" -"checksum shannon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7ea5b41c9427b56caa7b808cb548a04fb50bb5b9e98590b53f28064ff4174561" -"checksum shell-words 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6fa3938c99da4914afedd13bf3d79bcb6c277d1b2c398d23257a304d9e1b074" -"checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" -"checksum signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94f478ede9f64724c5d173d7bb56099ec3e2d9fc2774aac65d34b8b890405f41" -"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23" -"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" -"checksum smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c8cbcd6df1e117c2210e13ab5109635ad68a929fcbb8964dc965b76cb5ee013" -"checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" -"checksum smallvec 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7acad6f34eb9e8a259d3283d1e8c1d34d7415943d4895f65cc73813c7396fc85" -"checksum socket2 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" -"checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" -"checksum stdweb 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e" -"checksum stream-cipher 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8131256a5896cabcf5eb04f4d6dacbe1aefda854b0d9896e09cb58829ec5638c" -"checksum strsim 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" -"checksum strum 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b" -"checksum strum_macros 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c" -"checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" -"checksum syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "fb7f4c519df8c117855e19dd8cc851e89eb746fe7a73f0157e0d95fdec5369b0" -"checksum synstructure 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" -"checksum system-deps 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0f3ecc17269a19353b3558b313bba738b25d82993e30d62a18406a24aba4649b" -"checksum take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b157868d8ac1f56b64604539990685fa7611d8fa9e5476cf0c02cf34d32917c5" -"checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" -"checksum tar 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "489997b7557e9a43e192c527face4feacc78bfbe6eed67fd55c4c9e381cba290" -"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" -"checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" -"checksum thiserror 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "318234ffa22e0920fe9a40d7b8369b5f649d490980cf7aadcf1eb91594869b42" -"checksum thiserror-impl 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "cae2447b6282786c3493999f40a9be2a6ad20cb8bd268b0a0dbf5a065535c0ab" -"checksum time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" -"checksum tinyvec 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "53953d2d3a5ad81d9f844a32f14ebb121f50b650cd59d0ee2a07cf13c617efed" -"checksum tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" -"checksum tokio-codec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "25b2998660ba0e70d18684de5d06b70b70a3a747469af9dea7618cc59e75976b" -"checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71" -"checksum tokio-current-thread 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b1de0e32a83f131e002238d7ccde18211c0a5397f60cbfffcb112868c2e0e20e" -"checksum tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "fb2d1b8f4548dbf5e1f7818512e9c406860678f29c300cdf0ebac72d1a3a1671" -"checksum tokio-fs 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "297a1206e0ca6302a0eed35b700d292b275256f596e2f3fea7729d5e629b6ff4" -"checksum tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" -"checksum tokio-process 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "382d90f43fa31caebe5d3bc6cfd854963394fff3b8cb59d5146607aaae7e7e43" -"checksum tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fbb47ae81353c63c487030659494b295f6cb6576242f907f203473b191b0389" -"checksum tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "09bc590ec4ba8ba87652da2068d150dcada2cfa2e07faae270a5e0409aa51351" -"checksum tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162" -"checksum tokio-signal 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c34c6e548f101053321cba3da7cbb87a610b85555884c41b07da2eb91aff12" -"checksum tokio-sync 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "edfe50152bc8164fcc456dab7891fa9bf8beaf01c5ee7e1dd43a397c3cf87dee" -"checksum tokio-tcp 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "98df18ed66e3b72e742f185882a9e201892407957e45fbff8da17ae7a7c51f72" -"checksum tokio-threadpool 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "df720b6581784c118f0eb4310796b12b1d242a7eb95f716a8367855325c25f89" -"checksum tokio-timer 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "93044f2d313c95ff1cb7809ce9a7a05735b012288a888b62d4434fd58c94f296" -"checksum tokio-udp 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a0b10e610b39c38b031a2fcab08e4b82f16ece36504988dcbd81dbba650d82" -"checksum tokio-uds 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ab57a4ac4111c8c9dbcf70779f6fc8bc35ae4b2454809febac840ad19bd7e4e0" -"checksum toml 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)" = "75cf45bb0bef80604d001caaec0d09da99611b3c0fd39d3080468875cdb65645" -"checksum try-lock 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee2aa4715743892880f70885373966c83d73ef1b0838a664ef0c76fffd35e7c2" -"checksum typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" -"checksum unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -"checksum unicode-normalization 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6fb19cf769fa8c6a80a162df694621ebeb4dafb606470b2b2fce0be40a98a977" -"checksum unicode-segmentation 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" -"checksum unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" -"checksum unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" -"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -"checksum untrusted 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" -"checksum ureq 0.11.4 (registry+https://github.com/rust-lang/crates.io-index)" = "801125e6d1ba6864cf3a5a92cfb2f0b0a3ee73e40602a0cd206ad2f3c040aa96" -"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" -"checksum url 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5909f2b0817350449ed73e8bcd81c8c3c8d9a7a5d8acba4b27db277f1868976e" -"checksum uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11" -"checksum vergen 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ce50d8996df1f85af15f2cd8d33daae6e479575123ef4314a51a70a230739cb" -"checksum version-compare 0.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1" -"checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" -"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum vorbis 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "5e8a194457075360557b82dac78f7ca2d65bbb6679bccfabae5f7c8c706cc776" -"checksum vorbis-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3a0a8d7034313748da1d84b0adfa501f83f9ec83250f37fbacfa92a3580327c4" -"checksum vorbisfile-sys 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "4f4306d7e1ac4699b55e20de9483750b90c250913188efd7484db6bfbe9042d1" -"checksum walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" -"checksum want 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a05d9d966753fa4b5c8db73fcab5eed4549cfe0e1e4e66911e5564a0085c35d1" -"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" -"checksum wasm-bindgen 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)" = "3cd364751395ca0f68cafb17666eee36b63077fb5ecd972bbcd74c90c4bf736e" -"checksum wasm-bindgen-backend 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)" = "1114f89ab1f4106e5b55e688b828c0ab0ea593a1ea7c094b141b14cbaaec2d62" -"checksum wasm-bindgen-macro 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6ac8995ead1f084a8dea1e65f194d0973800c7f571f6edd70adf06ecf77084" -"checksum wasm-bindgen-macro-support 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a48c72f299d80557c7c62e37e7225369ecc0c963964059509fbafe917c7549" -"checksum wasm-bindgen-shared 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)" = "7e7811dd7f9398f14cc76efd356f98f03aa30419dea46aa810d71e819fc97158" -"checksum web-sys 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)" = "222b1ef9334f92a21d3fb53dc3fd80f30836959a90f9274a626d7e06315ba3c3" -"checksum webpki 0.21.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ab146130f5f790d45f82aeeb09e55a256573373ec64409fc19a6fb82fb1032ae" -"checksum webpki-roots 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "91cd5736df7f12a964a5067a12c62fa38e1bd8080aff1f80bc29be7c80d19ab4" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" -"checksum xattr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" -"checksum zerocopy 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6580539ad917b7c026220c4b3f2c08d52ce54d6ce0dc491e66002e35388fab46" -"checksum zerocopy-derive 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d498dbd1fd7beb83c86709ae1c33ca50942889473473d287d56ce4770a18edfb" + "proc-macro2", + "syn", + "synstructure", +] diff --git a/Cargo.toml b/Cargo.toml index f56649d08..cba117d50 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,8 +49,8 @@ num-bigint = "0.3" protobuf = "~2.14.0" rand = "0.7" rpassword = "5.0" -rpassword = "3.0" -tokio = "0.1" +# tokio = "0.1" +tokio = { version = "0.2", features = ["rt-core"] } tokio-io = "0.1" tokio-process = "0.2" tokio-signal = "0.2" From 0892587c0ef88d7ee6b1aaab604525b88c760b43 Mon Sep 17 00:00:00 2001 From: ashthespy Date: Sat, 23 Jan 2021 22:21:42 +0000 Subject: [PATCH 11/75] [Core] WIP: Sessions --- core/src/session.rs | 214 +++++++++++++++++++++----------------------- 1 file changed, 102 insertions(+), 112 deletions(-) diff --git a/core/src/session.rs b/core/src/session.rs index 821ae8747..9a8df2b7b 100644 --- a/core/src/session.rs +++ b/core/src/session.rs @@ -10,13 +10,7 @@ use bytes::Bytes; // use tokio::runtime::{current_thread, current_thread::Handle}; // use futures::future::{IntoFuture, Remote}; -use futures::{ - channel::mpsc, - // future::{IntoFuture, Remote}, - Future, - Stream, - TryFutureExt, -}; +use futures::{channel::mpsc, future, Future, Stream, StreamExt, TryFutureExt}; use std::{ pin::Pin, task::{Context, Poll}, @@ -25,14 +19,14 @@ use std::{ use tokio::runtime::Handle; use crate::apresolve::apresolve_or_fallback; -use crate::audio_key::AudioKeyManager; +// use crate::audio_key::AudioKeyManager; use crate::authentication::Credentials; use crate::cache::Cache; -use crate::channel::ChannelManager; -use crate::component::Lazy; +// use crate::channel::ChannelManager; +// use crate::component::Lazy; use crate::config::SessionConfig; use crate::connection; -use crate::mercury::MercuryManager; +// use crate::mercury::MercuryManager; struct SessionData { country: String, @@ -45,13 +39,12 @@ struct SessionInternal { config: SessionConfig, data: RwLock, - tx_connection: mpsc::UnboundedSender<(u8, Vec)>, + tx_connection: mpsc::UnboundedSender)>>, - audio_key: Lazy, - channel: Lazy, - mercury: Lazy, + // audio_key: Lazy, + // channel: Lazy, + // mercury: Lazy, cache: Option>, - handle: Mutex, session_id: usize, } @@ -71,42 +64,44 @@ impl Session { cache: Option, handle: Handle, ) -> Result { - unimplemented!() - // let access_point_addr = - // apresolve_or_fallback::(&config.proxy, &config.ap_port).await?; - // - // let proxy = config.proxy.clone(); - // info!("Connecting to AP \"{}\"", access_point_addr); - // let connection = connection::connect(access_point_addr, &proxy); - // - // let device_id = config.device_id.clone(); - // let authentication = connection.and_then(move |connection| { - // connection::authenticate(connection, credentials, device_id) - // }); - // - // let result = authentication.map(move |(transport, reusable_credentials)| { - // info!("Authenticated as \"{}\" !", reusable_credentials.username); - // if let Some(ref cache) = cache { - // cache.save_credentials(&reusable_credentials); - // } - // - // let (session, task) = Session::create( - // &handle, - // transport, - // config, - // cache, - // reusable_credentials.username.clone(), - // ); - // - // tokio::spawn(task.map_err(|e| { - // error!("SessionError: {}", e.to_string()); - // std::process::exit(0); - // })); - // - // session - // }); - // - // result + let access_point_addr = + apresolve_or_fallback::(&config.proxy, &config.ap_port).await?; + + let proxy = config.proxy.clone(); + info!("Connecting to AP \"{}\"", access_point_addr); + let connection = connection::connect(access_point_addr, &proxy); + + let device_id = config.device_id.clone(); + let authentication = connection.and_then(move |connection| { + connection::authenticate(connection, credentials, device_id) + }); + + let result = match authentication.await { + Ok((transport, reusable_credentials)) => { + info!("Authenticated as \"{}\" !", reusable_credentials.username); + if let Some(ref cache) = cache { + cache.save_credentials(&reusable_credentials); + } + + let (session, tasks) = Session::create( + &handle, + transport, + config, + cache, + reusable_credentials.username.clone(), + ); + + tokio::task::spawn_local(async move { tasks }); + + Ok(session) + } + Err(e) => { + error!("Unable to Connect"); + Err(e.into()) + } + }; + + result } fn create( @@ -115,7 +110,7 @@ impl Session { config: SessionConfig, cache: Option, username: String, - ) -> (Session, Box>>) { + ) -> (Session, Box, Result<()>)>>) { let (sink, stream) = transport.split(); let (sender_tx, sender_rx) = mpsc::unbounded(); @@ -124,7 +119,7 @@ impl Session { debug!("new Session[{}]", session_id); let session = Session(Arc::new(SessionInternal { - config: config, + config, data: RwLock::new(SessionData { country: String::new(), canonical_username: username, @@ -136,57 +131,52 @@ impl Session { cache: cache.map(Arc::new), - audio_key: Lazy::new(), - channel: Lazy::new(), - mercury: Lazy::new(), - + // audio_key: Lazy::new(), + // channel: Lazy::new(), + // mercury: Lazy::new(), handle: Mutex::new(handle.clone()), - session_id: session_id, + session_id, })); let sender_task = sender_rx - .map_err(|e| -> io::Error { panic!(e) }) .forward(sink) - .map(|_| ()); + .map_err(|e| -> Box { Box::new(e) }); + let receiver_task = DispatchTask(stream, session.weak()); - let task = Box::new( - (receiver_task, sender_task) - .into_future() - .map(|((), ())| ()), - ); + let task = Box::new(future::join(receiver_task, sender_task)); (session, task) } - pub fn audio_key(&self) -> &AudioKeyManager { - self.0.audio_key.get(|| AudioKeyManager::new(self.weak())) - } + // pub fn audio_key(&self) -> &AudioKeyManager { + // self.0.audio_key.get(|| AudioKeyManager::new(self.weak())) + // } - pub fn channel(&self) -> &ChannelManager { - self.0.channel.get(|| ChannelManager::new(self.weak())) - } + // pub fn channel(&self) -> &ChannelManager { + // self.0.channel.get(|| ChannelManager::new(self.weak())) + // } - pub fn mercury(&self) -> &MercuryManager { - self.0.mercury.get(|| MercuryManager::new(self.weak())) - } + // pub fn mercury(&self) -> &MercuryManager { + // self.0.mercury.get(|| MercuryManager::new(self.weak())) + // } pub fn time_delta(&self) -> i64 { self.0.data.read().unwrap().time_delta } // Spawn a future directly - pub fn spawn(&self, f: F) - where - F: Future + Send + 'static, - { - let handle = self.0.handle.lock().unwrap(); - let spawn_res = handle.spawn(f); - match spawn_res { - Ok(_) => (), - Err(e) => error!("Session SpawnErr {:?}", e), - } - } + // pub fn spawn(&self, f: F) + // where + // F: Future + Send + 'static, + // { + // let handle = self.0.handle.lock().unwrap(); + // let spawn_res = handle.spawn(f); + // match spawn_res { + // Ok(_) => (), + // Err(e) => error!("Session SpawnErr {:?}", e), + // } + // } // pub fn spawn(&self, f: F) // where @@ -218,7 +208,7 @@ impl Session { ); } - #[cfg_attr(feature = "cargo-clippy", allow(match_same_arms))] + // #[cfg_attr(feature = "cargo-clippy", allow(match_same_arms))] fn dispatch(&self, cmd: u8, data: Bytes) { match cmd { 0x4 => { @@ -241,15 +231,18 @@ impl Session { self.0.data.write().unwrap().country = country; } - 0x9 | 0xa => self.channel().dispatch(cmd, data), - 0xd | 0xe => self.audio_key().dispatch(cmd, data), - 0xb2..=0xb6 => self.mercury().dispatch(cmd, data), + // 0x9 | 0xa => self.channel().dispatch(cmd, data), + // 0xd | 0xe => self.audio_key().dispatch(cmd, data), + // 0xb2..=0xb6 => self.mercury().dispatch(cmd, data), _ => trace!("Unknown dispatch cmd :{:?} {:?}", cmd, data), } } pub fn send_packet(&self, cmd: u8, data: Vec) { - self.0.tx_connection.unbounded_send((cmd, data)).unwrap(); + self.0 + .tx_connection + .unbounded_send(Ok((cmd, data))) + .unwrap(); } pub fn cache(&self) -> Option<&Arc> { @@ -283,8 +276,8 @@ impl Session { pub fn shutdown(&self) { debug!("Invalidating session[{}]", self.0.session_id); self.0.data.write().unwrap().invalid = true; - self.mercury().shutdown(); - self.channel().shutdown(); + // self.mercury().shutdown(); + // self.channel().shutdown(); } pub fn is_invalid(&self) -> bool { @@ -311,40 +304,37 @@ impl Drop for SessionInternal { } } -// type SErr = ::std::fmt::Debug; - struct DispatchTask(S, SessionWeak) where - S: Stream>; + S: Stream> + Unpin; -impl Future for DispatchTask +impl>> Future for DispatchTask where - // SErr: ::std::fmt::Debug, - S: Stream>, + S: Stream> + Unpin, { - type Output = Result<((), ())>; + type Output = Result<()>; - fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { + fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll { let session = match self.1.try_upgrade() { Some(session) => session, - None => return Poll::Ready(()), + None => return Poll::Ready(Ok(())), }; loop { - let (cmd, data) = match self.unwrap().0.poll() { - Poll::Ready(Ok(Some(t))) => t, - Poll::Ready(Ok(None)) => { - warn!("Connection to server closed."); + let (cmd, data) = match Pin::new(&mut self.0).poll_next(cx) { + Poll::Ready(Some(Ok(t))) => t, + Poll::Ready(Some(Err(e))) => { + warn!("Server Connectioned errored"); session.shutdown(); - return Ok(Poll::Ready(())); + return Poll::Ready(Err(Box::new(e))); } - Poll::Pending => return Poll::Pending, - Poll::Ready(Err(e)) => { + Poll::Ready(None) => { + warn!("Connection to server closed."); session.shutdown(); - return Err(From::from(e)); + return Poll::Ready(Ok(())); } + Poll::Pending => return Poll::Pending, }; - session.dispatch(cmd, data); } } @@ -352,7 +342,7 @@ where impl Drop for DispatchTask where - S: Stream>, + S: Stream> + Unpin, { fn drop(&mut self) { debug!("drop Dispatch"); From 40e6355c34a72f7ac0980770082e06099eb91451 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Thu, 21 Jan 2021 21:49:39 +0100 Subject: [PATCH 12/75] Migrate core to tokio 1.0 --- core/Cargo.toml | 26 +++-- core/src/apresolve.rs | 126 +++++++++------------- core/src/audio_key.rs | 22 +--- core/src/authentication.rs | 10 +- core/src/channel.rs | 91 +++++++++------- core/src/component.rs | 26 ----- core/src/connection/codec.rs | 7 +- core/src/connection/handshake.rs | 173 +++++++++---------------------- core/src/connection/mod.rs | 122 +++++++++------------- core/src/diffie_hellman.rs | 12 +-- core/src/keymaster.rs | 20 ++-- core/src/lib.rs | 24 ++--- core/src/mercury/mod.rs | 100 +++++++++--------- core/src/mercury/sender.rs | 35 ++++--- core/src/proxytunnel.rs | 133 ++++++------------------ core/src/session.rs | 146 +++++++++++--------------- 16 files changed, 409 insertions(+), 664 deletions(-) diff --git a/core/Cargo.toml b/core/Cargo.toml index 8511878c3..a9fcc246b 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -13,34 +13,32 @@ path = "../protocol" version = "0.1.3" [dependencies] +aes = "0.6" base64 = "0.13" -byteorder = "1.3" -bytes = "0.4" -error-chain = { version = "0.12", default_features = false } -futures = "0.1" +byteorder = "1.4" +bytes = "1.0" +futures = { version = "0.3", features = ["bilock", "unstable"] } +hmac = "0.7" httparse = "1.3" -hyper = "0.11" -hyper-proxy = { version = "0.4", default_features = false } -lazy_static = "1.3" +hyper = { version = "0.14", features = ["client", "tcp", "http1", "http2", "stream"] } log = "0.4" num-bigint = "0.3" num-integer = "0.1" num-traits = "0.2" +once_cell = "1.5.2" +pbkdf2 = "0.3" +pin-project = "1.0" protobuf = "~2.14.0" rand = "0.7" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" +sha-1 = "~0.8" shannon = "0.2.0" -tokio-codec = "0.1" -tokio-core = "0.1" -tokio-io = "0.1" +tokio = { version = "1.0", features = ["io-util", "rt-multi-thread", "macros" ] } +tokio-util = { version = "0.6", features = ["codec"] } url = "1.7" uuid = { version = "0.8", features = ["v4"] } -sha-1 = "0.8" -hmac = "0.7" -pbkdf2 = "0.3" -aes = "0.3" [build-dependencies] rand = "0.7" diff --git a/core/src/apresolve.rs b/core/src/apresolve.rs index 94d942440..07c2958f4 100644 --- a/core/src/apresolve.rs +++ b/core/src/apresolve.rs @@ -1,101 +1,69 @@ const AP_FALLBACK: &'static str = "ap.spotify.com:443"; const APRESOLVE_ENDPOINT: &'static str = "http://apresolve.spotify.com/"; -use futures::{Future, Stream}; -use hyper::client::HttpConnector; -use hyper::{self, Client, Method, Request, Uri}; -use hyper_proxy::{Intercept, Proxy, ProxyConnector}; -use serde_json; -use std::str::FromStr; -use tokio_core::reactor::Handle; +use hyper::{Body, Client, Method, Request, Uri}; +use std::error::Error; use url::Url; -error_chain! {} - #[derive(Clone, Debug, Serialize, Deserialize)] pub struct APResolveData { ap_list: Vec, } -fn apresolve( - handle: &Handle, - proxy: &Option, - ap_port: &Option, -) -> Box> { - let url = Uri::from_str(APRESOLVE_ENDPOINT).expect("invalid AP resolve URL"); - let use_proxy = proxy.is_some(); +async fn apresolve(proxy: &Option, ap_port: &Option) -> Result> { + let port = ap_port.unwrap_or(443); + + let req = Request::builder() + .method(Method::GET) + .uri( + APRESOLVE_ENDPOINT + .parse::() + .expect("invalid AP resolve URL"), + ) + .body(Body::empty())?; - let mut req = Request::new(Method::Get, url.clone()); - let response = match *proxy { - Some(ref val) => { - let proxy_url = Uri::from_str(val.as_str()).expect("invalid http proxy"); - let proxy = Proxy::new(Intercept::All, proxy_url); - let connector = HttpConnector::new(4, handle); + let client = if proxy.is_some() { + todo!("proxies not yet supported") + /*let proxy = { + let proxy_url = val.as_str().parse().expect("invalid http proxy"); + let mut proxy = Proxy::new(Intercept::All, proxy_url); + let connector = HttpConnector::new(); let proxy_connector = ProxyConnector::from_proxy_unsecured(connector, proxy); - if let Some(headers) = proxy_connector.http_headers(&url) { - req.headers_mut().extend(headers.iter()); - req.set_proxy(true); - } - let client = Client::configure().connector(proxy_connector).build(handle); - client.request(req) - } - _ => { - let client = Client::new(handle); - client.request(req) - } - }; + proxy_connector + }; - let body = response.and_then(|response| { - response.body().fold(Vec::new(), |mut acc, chunk| { - acc.extend_from_slice(chunk.as_ref()); - Ok::<_, hyper::Error>(acc) - }) - }); - let body = body.then(|result| result.chain_err(|| "HTTP error")); - let body = - body.and_then(|body| String::from_utf8(body).chain_err(|| "invalid UTF8 in response")); + if let Some(headers) = proxy.http_headers(&APRESOLVE_ENDPOINT.parse().unwrap()) { + req.headers_mut().extend(headers.clone()); + }; + Client::builder().build(proxy)*/ + } else { + Client::new() + }; - let data = body - .and_then(|body| serde_json::from_str::(&body).chain_err(|| "invalid JSON")); + let response = client.request(req).await?; - let p = ap_port.clone(); + let body = hyper::body::to_bytes(response.into_body()).await?; + let data: APResolveData = serde_json::from_slice(body.as_ref())?; - let ap = data.and_then(move |data| { - let mut aps = data.ap_list.iter().filter(|ap| { - if p.is_some() { - Uri::from_str(ap).ok().map_or(false, |uri| { - uri.port().map_or(false, |port| port == p.unwrap()) - }) - } else if use_proxy { - // It is unlikely that the proxy will accept CONNECT on anything other than 443. - Uri::from_str(ap) - .ok() - .map_or(false, |uri| uri.port().map_or(false, |port| port == 443)) + let ap = if ap_port.is_some() || proxy.is_some() { + data.ap_list.into_iter().find_map(|ap| { + if ap.parse::().ok()?.port()? == port { + Some(ap) } else { - true + None } - }); - - let ap = aps.next().ok_or("empty AP List")?; - Ok(ap.clone()) - }); - - Box::new(ap) + }) + } else { + data.ap_list.into_iter().next() + } + .ok_or("empty AP List")?; + Ok(ap) } -pub(crate) fn apresolve_or_fallback( - handle: &Handle, - proxy: &Option, - ap_port: &Option, -) -> Box> -where - E: 'static, -{ - let ap = apresolve(handle, proxy, ap_port).or_else(|e| { - warn!("Failed to resolve Access Point: {}", e.description()); +pub async fn apresolve_or_fallback(proxy: &Option, ap_port: &Option) -> String { + apresolve(proxy, ap_port).await.unwrap_or_else(|e| { + warn!("Failed to resolve Access Point: {}", e); warn!("Using fallback \"{}\"", AP_FALLBACK); - Ok(AP_FALLBACK.into()) - }); - - Box::new(ap) + AP_FALLBACK.into() + }) } diff --git a/core/src/audio_key.rs b/core/src/audio_key.rs index 1e5310c21..b9f0c2328 100644 --- a/core/src/audio_key.rs +++ b/core/src/audio_key.rs @@ -1,7 +1,6 @@ use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; use bytes::Bytes; -use futures::sync::oneshot; -use futures::{Async, Future, Poll}; +use futures::channel::oneshot; use std::collections::HashMap; use std::io::Write; @@ -47,7 +46,7 @@ impl AudioKeyManager { } } - pub fn request(&self, track: SpotifyId, file: FileId) -> AudioKeyFuture { + pub async fn request(&self, track: SpotifyId, file: FileId) -> Result { let (tx, rx) = oneshot::channel(); let seq = self.lock(move |inner| { @@ -57,7 +56,7 @@ impl AudioKeyManager { }); self.send_key_request(seq, track, file); - AudioKeyFuture(rx) + rx.await.map_err(|_| AudioKeyError)? } fn send_key_request(&self, seq: u32, track: SpotifyId, file: FileId) { @@ -70,18 +69,3 @@ impl AudioKeyManager { self.session().send_packet(0xc, data) } } - -pub struct AudioKeyFuture(oneshot::Receiver>); -impl Future for AudioKeyFuture { - type Item = T; - type Error = AudioKeyError; - - fn poll(&mut self) -> Poll { - match self.0.poll() { - Ok(Async::Ready(Ok(value))) => Ok(Async::Ready(value)), - Ok(Async::Ready(Err(err))) => Err(err), - Ok(Async::NotReady) => Ok(Async::NotReady), - Err(oneshot::Canceled) => Err(AudioKeyError), - } - } -} diff --git a/core/src/authentication.rs b/core/src/authentication.rs index 36cbd4390..dd39fd855 100644 --- a/core/src/authentication.rs +++ b/core/src/authentication.rs @@ -1,11 +1,9 @@ use aes::Aes192; -use base64; +use aes::NewBlockCipher; use byteorder::{BigEndian, ByteOrder}; use hmac::Hmac; use pbkdf2::pbkdf2; use protobuf::ProtobufEnum; -use serde; -use serde_json; use sha1::{Digest, Sha1}; use std::fs::File; use std::io::{self, Read, Write}; @@ -76,9 +74,9 @@ impl Credentials { // decrypt data using ECB mode without padding let blob = { - use aes::block_cipher_trait::generic_array::typenum::Unsigned; - use aes::block_cipher_trait::generic_array::GenericArray; - use aes::block_cipher_trait::BlockCipher; + use aes::cipher::generic_array::typenum::Unsigned; + use aes::cipher::generic_array::GenericArray; + use aes::cipher::BlockCipher; let mut data = base64::decode(encrypted_blob).unwrap(); let cipher = Aes192::new(GenericArray::from_slice(&key)); diff --git a/core/src/channel.rs b/core/src/channel.rs index b614fac49..7ada05d5e 100644 --- a/core/src/channel.rs +++ b/core/src/channel.rs @@ -1,9 +1,12 @@ use byteorder::{BigEndian, ByteOrder}; use bytes::Bytes; -use futures::sync::{mpsc, BiLock}; -use futures::{Async, Poll, Stream}; -use std::collections::HashMap; -use std::time::Instant; +use futures::{channel::mpsc, lock::BiLock, Stream, StreamExt}; +use std::{ + collections::HashMap, + pin::Pin, + task::{Context, Poll}, + time::Instant, +}; use crate::util::SeqGenerator; @@ -101,12 +104,10 @@ impl ChannelManager { } impl Channel { - fn recv_packet(&mut self) -> Poll { - let (cmd, packet) = match self.receiver.poll() { - Ok(Async::Ready(Some(t))) => t, - Ok(Async::Ready(None)) => return Err(ChannelError), // The channel has been closed. - Ok(Async::NotReady) => return Ok(Async::NotReady), - Err(()) => unreachable!(), + fn recv_packet(&mut self, cx: &mut Context<'_>) -> Poll> { + let (cmd, packet) = match self.receiver.poll_next_unpin(cx) { + Poll::Pending => return Poll::Pending, + Poll::Ready(o) => o.ok_or(ChannelError)?, }; if cmd == 0xa { @@ -115,9 +116,9 @@ impl Channel { self.state = ChannelState::Closed; - Err(ChannelError) + Poll::Ready(Err(ChannelError)) } else { - Ok(Async::Ready(packet)) + Poll::Ready(Ok(packet)) } } @@ -129,16 +130,19 @@ impl Channel { } impl Stream for Channel { - type Item = ChannelEvent; - type Error = ChannelError; + type Item = Result; - fn poll(&mut self) -> Poll, Self::Error> { + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { loop { match self.state.clone() { ChannelState::Closed => panic!("Polling already terminated channel"), ChannelState::Header(mut data) => { if data.len() == 0 { - data = try_ready!(self.recv_packet()); + data = match self.recv_packet(cx) { + Poll::Ready(Ok(x)) => x, + Poll::Ready(Err(x)) => return Poll::Ready(Some(Err(x))), + Poll::Pending => return Poll::Pending, + }; } let length = BigEndian::read_u16(data.split_to(2).as_ref()) as usize; @@ -152,19 +156,23 @@ impl Stream for Channel { self.state = ChannelState::Header(data); let event = ChannelEvent::Header(header_id, header_data); - return Ok(Async::Ready(Some(event))); + return Poll::Ready(Some(Ok(event))); } } ChannelState::Data => { - let data = try_ready!(self.recv_packet()); + let data = match self.recv_packet(cx) { + Poll::Ready(Ok(x)) => x, + Poll::Ready(Err(x)) => return Poll::Ready(Some(Err(x))), + Poll::Pending => return Poll::Pending, + }; if data.len() == 0 { self.receiver.close(); self.state = ChannelState::Closed; - return Ok(Async::Ready(None)); + return Poll::Ready(None); } else { let event = ChannelEvent::Data(data); - return Ok(Async::Ready(Some(event))); + return Poll::Ready(Some(Ok(event))); } } } @@ -173,38 +181,45 @@ impl Stream for Channel { } impl Stream for ChannelData { - type Item = Bytes; - type Error = ChannelError; + type Item = Result; - fn poll(&mut self) -> Poll, Self::Error> { - let mut channel = match self.0.poll_lock() { - Async::Ready(c) => c, - Async::NotReady => return Ok(Async::NotReady), + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + let mut channel = match self.0.poll_lock(cx) { + Poll::Ready(c) => c, + Poll::Pending => return Poll::Pending, }; loop { - match try_ready!(channel.poll()) { + let x = match channel.poll_next_unpin(cx) { + Poll::Ready(x) => x.transpose()?, + Poll::Pending => return Poll::Pending, + }; + match x { Some(ChannelEvent::Header(..)) => (), - Some(ChannelEvent::Data(data)) => return Ok(Async::Ready(Some(data))), - None => return Ok(Async::Ready(None)), + Some(ChannelEvent::Data(data)) => return Poll::Ready(Some(Ok(data))), + None => return Poll::Ready(None), } } } } impl Stream for ChannelHeaders { - type Item = (u8, Vec); - type Error = ChannelError; + type Item = Result<(u8, Vec), ChannelError>; - fn poll(&mut self) -> Poll, Self::Error> { - let mut channel = match self.0.poll_lock() { - Async::Ready(c) => c, - Async::NotReady => return Ok(Async::NotReady), + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + let mut channel = match self.0.poll_lock(cx) { + Poll::Ready(c) => c, + Poll::Pending => return Poll::Pending, }; - match try_ready!(channel.poll()) { - Some(ChannelEvent::Header(id, data)) => Ok(Async::Ready(Some((id, data)))), - Some(ChannelEvent::Data(..)) | None => Ok(Async::Ready(None)), + let x = match channel.poll_next_unpin(cx) { + Poll::Ready(x) => x.transpose()?, + Poll::Pending => return Poll::Pending, + }; + + match x { + Some(ChannelEvent::Header(id, data)) => Poll::Ready(Some(Ok((id, data)))), + Some(ChannelEvent::Data(..)) | None => Poll::Ready(None), } } } diff --git a/core/src/component.rs b/core/src/component.rs index 50ab7b37e..a761c4551 100644 --- a/core/src/component.rs +++ b/core/src/component.rs @@ -35,29 +35,3 @@ macro_rules! component { } } } - -use std::cell::UnsafeCell; -use std::sync::Mutex; - -pub(crate) struct Lazy(Mutex, UnsafeCell>); -unsafe impl Sync for Lazy {} -unsafe impl Send for Lazy {} - -#[cfg_attr(feature = "cargo-clippy", allow(mutex_atomic))] -impl Lazy { - pub(crate) fn new() -> Lazy { - Lazy(Mutex::new(false), UnsafeCell::new(None)) - } - - pub(crate) fn get T>(&self, f: F) -> &T { - let mut inner = self.0.lock().unwrap(); - if !*inner { - unsafe { - *self.1.get() = Some(f()); - } - *inner = true; - } - - unsafe { &*self.1.get() }.as_ref().unwrap() - } -} diff --git a/core/src/connection/codec.rs b/core/src/connection/codec.rs index fa4cd9d99..ead07b6ec 100644 --- a/core/src/connection/codec.rs +++ b/core/src/connection/codec.rs @@ -2,7 +2,7 @@ use byteorder::{BigEndian, ByteOrder}; use bytes::{BufMut, Bytes, BytesMut}; use shannon::Shannon; use std::io; -use tokio_io::codec::{Decoder, Encoder}; +use tokio_util::codec::{Decoder, Encoder}; const HEADER_SIZE: usize = 3; const MAC_SIZE: usize = 4; @@ -35,8 +35,7 @@ impl APCodec { } } -impl Encoder for APCodec { - type Item = (u8, Vec); +impl Encoder<(u8, Vec)> for APCodec { type Error = io::Error; fn encode(&mut self, item: (u8, Vec), buf: &mut BytesMut) -> io::Result<()> { @@ -45,7 +44,7 @@ impl Encoder for APCodec { buf.reserve(3 + payload.len()); buf.put_u8(cmd); - buf.put_u16_be(payload.len() as u16); + buf.put_u16(payload.len() as u16); buf.extend_from_slice(&payload); self.encode_cipher.nonce_u32(self.encode_nonce); diff --git a/core/src/connection/handshake.rs b/core/src/connection/handshake.rs index 220ab6e83..3810fc96e 100644 --- a/core/src/connection/handshake.rs +++ b/core/src/connection/handshake.rs @@ -1,14 +1,11 @@ use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; -use futures::{Async, Future, Poll}; use hmac::{Hmac, Mac}; use protobuf::{self, Message}; use rand::thread_rng; use sha1::Sha1; -use std::io::{self, Read}; -use std::marker::PhantomData; -use tokio_codec::{Decoder, Framed}; -use tokio_io::io::{read_exact, write_all, ReadExact, Window, WriteAll}; -use tokio_io::{AsyncRead, AsyncWrite}; +use std::io; +use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; +use tokio_util::codec::{Decoder, Framed}; use super::codec::APCodec; use crate::diffie_hellman::DHLocalKeys; @@ -16,72 +13,33 @@ use crate::protocol; use crate::protocol::keyexchange::{APResponseMessage, ClientHello, ClientResponsePlaintext}; use crate::util; -pub struct Handshake { - keys: DHLocalKeys, - state: HandshakeState, -} - -enum HandshakeState { - ClientHello(WriteAll>), - APResponse(RecvPacket), - ClientResponse(Option, WriteAll>), -} - -pub fn handshake(connection: T) -> Handshake { +pub async fn handshake( + mut connection: T, +) -> io::Result> { let local_keys = DHLocalKeys::random(&mut thread_rng()); - let client_hello = client_hello(connection, local_keys.public_key()); - - Handshake { - keys: local_keys, - state: HandshakeState::ClientHello(client_hello), - } + let gc = local_keys.public_key(); + let mut accumulator = client_hello(&mut connection, gc).await?; + let message: APResponseMessage = recv_packet(&mut connection, &mut accumulator).await?; + let remote_key = message + .get_challenge() + .get_login_crypto_challenge() + .get_diffie_hellman() + .get_gs() + .to_owned(); + + let shared_secret = local_keys.shared_secret(&remote_key); + let (challenge, send_key, recv_key) = compute_keys(&shared_secret, &accumulator); + let codec = APCodec::new(&send_key, &recv_key); + + client_response(&mut connection, challenge).await?; + + Ok(codec.framed(connection)) } -impl Future for Handshake { - type Item = Framed; - type Error = io::Error; - - fn poll(&mut self) -> Poll { - use self::HandshakeState::*; - loop { - self.state = match self.state { - ClientHello(ref mut write) => { - let (connection, accumulator) = try_ready!(write.poll()); - - let read = recv_packet(connection, accumulator); - APResponse(read) - } - - APResponse(ref mut read) => { - let (connection, message, accumulator) = try_ready!(read.poll()); - let remote_key = message - .get_challenge() - .get_login_crypto_challenge() - .get_diffie_hellman() - .get_gs() - .to_owned(); - - let shared_secret = self.keys.shared_secret(&remote_key); - let (challenge, send_key, recv_key) = - compute_keys(&shared_secret, &accumulator); - let codec = APCodec::new(&send_key, &recv_key); - - let write = client_response(connection, challenge); - ClientResponse(Some(codec), write) - } - - ClientResponse(ref mut codec, ref mut write) => { - let (connection, _) = try_ready!(write.poll()); - let codec = codec.take().unwrap(); - let framed = codec.framed(connection); - return Ok(Async::Ready(framed)); - } - } - } - } -} - -fn client_hello(connection: T, gc: Vec) -> WriteAll> { +async fn client_hello(connection: &mut T, gc: Vec) -> io::Result> +where + T: AsyncWrite + Unpin, +{ let mut packet = ClientHello::new(); packet .mut_build_info() @@ -106,13 +64,17 @@ fn client_hello(connection: T, gc: Vec) -> WriteAll(size).unwrap(); + as WriteBytesExt>::write_u32::(&mut buffer, size).unwrap(); packet.write_to_vec(&mut buffer).unwrap(); - write_all(connection, buffer) + connection.write_all(&buffer[..]).await?; + Ok(buffer) } -fn client_response(connection: T, challenge: Vec) -> WriteAll> { +async fn client_response(connection: &mut T, challenge: Vec) -> io::Result<()> +where + T: AsyncWrite + Unpin, +{ let mut packet = ClientResponsePlaintext::new(); packet .mut_login_crypto_response() @@ -123,70 +85,35 @@ fn client_response(connection: T, challenge: Vec) -> WriteAll let mut buffer = vec![]; let size = 4 + packet.compute_size(); - buffer.write_u32::(size).unwrap(); + as WriteBytesExt>::write_u32::(&mut buffer, size).unwrap(); packet.write_to_vec(&mut buffer).unwrap(); - write_all(connection, buffer) -} - -enum RecvPacket { - Header(ReadExact>>, PhantomData), - Body(ReadExact>>, PhantomData), + connection.write_all(&buffer[..]).await?; + Ok(()) } -fn recv_packet(connection: T, acc: Vec) -> RecvPacket +async fn recv_packet(connection: &mut T, acc: &mut Vec) -> io::Result where - T: Read, + T: AsyncRead + Unpin, M: Message, { - RecvPacket::Header(read_into_accumulator(connection, 4, acc), PhantomData) + let header = read_into_accumulator(connection, 4, acc).await?; + let size = BigEndian::read_u32(header) as usize; + let data = read_into_accumulator(connection, size - 4, acc).await?; + let message = protobuf::parse_from_bytes(data).unwrap(); + Ok(message) } -impl Future for RecvPacket -where - T: Read, - M: Message, -{ - type Item = (T, M, Vec); - type Error = io::Error; - - fn poll(&mut self) -> Poll { - use self::RecvPacket::*; - loop { - *self = match *self { - Header(ref mut read, _) => { - let (connection, header) = try_ready!(read.poll()); - let size = BigEndian::read_u32(header.as_ref()) as usize; - - let acc = header.into_inner(); - let read = read_into_accumulator(connection, size - 4, acc); - RecvPacket::Body(read, PhantomData) - } - - Body(ref mut read, _) => { - let (connection, data) = try_ready!(read.poll()); - let message = protobuf::parse_from_bytes(data.as_ref()).unwrap(); - - let acc = data.into_inner(); - return Ok(Async::Ready((connection, message, acc))); - } - } - } - } -} - -fn read_into_accumulator( - connection: T, +async fn read_into_accumulator<'a, T: AsyncRead + Unpin>( + connection: &mut T, size: usize, - mut acc: Vec, -) -> ReadExact>> { + acc: &'a mut Vec, +) -> io::Result<&'a mut [u8]> { let offset = acc.len(); acc.resize(offset + size, 0); - let mut window = Window::new(acc); - window.set_start(offset); - - read_exact(connection, window) + connection.read_exact(&mut acc[offset..]).await?; + Ok(&mut acc[offset..]) } fn compute_keys(shared_secret: &[u8], packets: &[u8]) -> (Vec, Vec, Vec) { diff --git a/core/src/connection/mod.rs b/core/src/connection/mod.rs index 72497795e..eba640700 100644 --- a/core/src/connection/mod.rs +++ b/core/src/connection/mod.rs @@ -4,13 +4,12 @@ mod handshake; pub use self::codec::APCodec; pub use self::handshake::handshake; -use futures::{Future, Sink, Stream}; +use futures::{SinkExt, StreamExt}; use protobuf::{self, Message}; use std::io; use std::net::ToSocketAddrs; -use tokio_codec::Framed; -use tokio_core::net::TcpStream; -use tokio_core::reactor::Handle; +use tokio::net::TcpStream; +use tokio_util::codec::Framed; use url::Url; use crate::authentication::Credentials; @@ -20,53 +19,36 @@ use crate::proxytunnel; pub type Transport = Framed; -pub fn connect( - addr: String, - handle: &Handle, - proxy: &Option, -) -> Box> { - let (addr, connect_url) = match *proxy { - Some(ref url) => { - info!("Using proxy \"{}\"", url); - match url.to_socket_addrs().and_then(|mut iter| { - iter.next().ok_or(io::Error::new( +pub async fn connect(addr: String, proxy: &Option) -> io::Result { + let socket = if let Some(proxy) = proxy { + info!("Using proxy \"{}\"", proxy); + let socket_addr = proxy.to_socket_addrs().and_then(|mut iter| { + iter.next().ok_or_else(|| { + io::Error::new( io::ErrorKind::NotFound, "Can't resolve proxy server address", - )) - }) { - Ok(socket_addr) => (socket_addr, Some(addr)), - Err(error) => return Box::new(futures::future::err(error)), - } - } - None => { - match addr.to_socket_addrs().and_then(|mut iter| { - iter.next().ok_or(io::Error::new( - io::ErrorKind::NotFound, - "Can't resolve server address", - )) - }) { - Ok(socket_addr) => (socket_addr, None), - Err(error) => return Box::new(futures::future::err(error)), - } - } + ) + }) + })?; + let socket = TcpStream::connect(&socket_addr).await?; + proxytunnel::connect(socket, &addr).await? + } else { + let socket_addr = addr.to_socket_addrs().and_then(|mut iter| { + iter.next().ok_or_else(|| { + io::Error::new(io::ErrorKind::NotFound, "Can't resolve server address") + }) + })?; + TcpStream::connect(&socket_addr).await? }; - let socket = TcpStream::connect(&addr, handle); - if let Some(connect_url) = connect_url { - let connection = socket - .and_then(move |socket| proxytunnel::connect(socket, &connect_url).and_then(handshake)); - Box::new(connection) - } else { - let connection = socket.and_then(handshake); - Box::new(connection) - } + handshake(socket).await } -pub fn authenticate( - transport: Transport, +pub async fn authenticate( + transport: &mut Transport, credentials: Credentials, - device_id: String, -) -> Box> { + device_id: &str, +) -> io::Result { use crate::protocol::authentication::{APWelcome, ClientResponseEncrypted, CpuFamily, Os}; use crate::protocol::keyexchange::APLoginFailed; @@ -91,41 +73,37 @@ pub fn authenticate( version::short_sha(), version::build_id() )); - packet.mut_system_info().set_device_id(device_id); + packet + .mut_system_info() + .set_device_id(device_id.to_string()); packet.set_version_string(version::version_string()); let cmd = 0xab; let data = packet.write_to_bytes().unwrap(); - Box::new( - transport - .send((cmd, data)) - .and_then(|transport| transport.into_future().map_err(|(err, _stream)| err)) - .and_then(|(packet, transport)| match packet { - Some((0xac, data)) => { - let welcome_data: APWelcome = - protobuf::parse_from_bytes(data.as_ref()).unwrap(); + transport.send((cmd, data)).await?; + let (cmd, data) = transport.next().await.expect("EOF")?; + match cmd { + 0xac => { + let welcome_data: APWelcome = protobuf::parse_from_bytes(data.as_ref()).unwrap(); - let reusable_credentials = Credentials { - username: welcome_data.get_canonical_username().to_owned(), - auth_type: welcome_data.get_reusable_auth_credentials_type(), - auth_data: welcome_data.get_reusable_auth_credentials().to_owned(), - }; + let reusable_credentials = Credentials { + username: welcome_data.get_canonical_username().to_owned(), + auth_type: welcome_data.get_reusable_auth_credentials_type(), + auth_data: welcome_data.get_reusable_auth_credentials().to_owned(), + }; - Ok((transport, reusable_credentials)) - } + Ok(reusable_credentials) + } - Some((0xad, data)) => { - let error_data: APLoginFailed = - protobuf::parse_from_bytes(data.as_ref()).unwrap(); - panic!( - "Authentication failed with reason: {:?}", - error_data.get_error_code() - ) - } + 0xad => { + let error_data: APLoginFailed = protobuf::parse_from_bytes(data.as_ref()).unwrap(); + panic!( + "Authentication failed with reason: {:?}", + error_data.get_error_code() + ) + } - Some((cmd, _)) => panic!("Unexpected packet {:?}", cmd), - None => panic!("EOF"), - }), - ) + _ => panic!("Unexpected packet {:?}", cmd), + } } diff --git a/core/src/diffie_hellman.rs b/core/src/diffie_hellman.rs index dec34a3b8..358901bea 100644 --- a/core/src/diffie_hellman.rs +++ b/core/src/diffie_hellman.rs @@ -1,12 +1,12 @@ use num_bigint::BigUint; -use num_traits::FromPrimitive; +use once_cell::sync::Lazy; use rand::Rng; use crate::util; -lazy_static! { - pub static ref DH_GENERATOR: BigUint = BigUint::from_u64(0x2).unwrap(); - pub static ref DH_PRIME: BigUint = BigUint::from_bytes_be(&[ +pub static DH_GENERATOR: Lazy = Lazy::new(|| BigUint::from_bytes_be(&[0x02])); +pub static DH_PRIME: Lazy = Lazy::new(|| { + BigUint::from_bytes_be(&[ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34, 0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74, 0x02, 0x0b, 0xbe, 0xa6, 0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e, @@ -14,8 +14,8 @@ lazy_static! { 0xf2, 0x5f, 0x14, 0x37, 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45, 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6, 0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x3a, 0x36, 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - ]); -} + ]) +}); pub struct DHLocalKeys { private_key: BigUint, diff --git a/core/src/keymaster.rs b/core/src/keymaster.rs index f2d7b772c..87b3f1e30 100644 --- a/core/src/keymaster.rs +++ b/core/src/keymaster.rs @@ -1,8 +1,4 @@ -use futures::Future; -use serde_json; - -use crate::mercury::MercuryError; -use crate::session::Session; +use crate::{mercury::MercuryError, session::Session}; #[derive(Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] @@ -13,20 +9,16 @@ pub struct Token { pub scope: Vec, } -pub fn get_token( +pub async fn get_token( session: &Session, client_id: &str, scopes: &str, -) -> Box> { +) -> Result { let url = format!( "hm://keymaster/token/authenticated?client_id={}&scope={}", client_id, scopes ); - Box::new(session.mercury().get(url).map(move |response| { - let data = response.payload.first().expect("Empty payload"); - let data = String::from_utf8(data.clone()).unwrap(); - let token: Token = serde_json::from_str(&data).unwrap(); - - token - })) + let response = session.mercury().get(url).await?; + let data = response.payload.first().expect("Empty payload"); + serde_json::from_slice(data.as_ref()).map_err(|_| MercuryError) } diff --git a/core/src/lib.rs b/core/src/lib.rs index c65878c2a..65f6f81bd 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -1,27 +1,23 @@ -#![cfg_attr(feature = "cargo-clippy", allow(unused_io_amount))] +#![allow(clippy::unused_io_amount)] -#[macro_use] -extern crate error_chain; -#[macro_use] -extern crate futures; -#[macro_use] -extern crate lazy_static; #[macro_use] extern crate log; #[macro_use] extern crate serde_derive; - +#[macro_use] +extern crate pin_project; extern crate aes; extern crate base64; extern crate byteorder; extern crate bytes; +extern crate futures; extern crate hmac; extern crate httparse; extern crate hyper; -extern crate hyper_proxy; extern crate num_bigint; extern crate num_integer; extern crate num_traits; +extern crate once_cell; extern crate pbkdf2; extern crate protobuf; extern crate rand; @@ -29,9 +25,8 @@ extern crate serde; extern crate serde_json; extern crate sha1; extern crate shannon; -extern crate tokio_codec; -extern crate tokio_core; -extern crate tokio_io; +extern crate tokio; +extern crate tokio_util; extern crate url; extern crate uuid; @@ -39,13 +34,14 @@ extern crate librespot_protocol as protocol; #[macro_use] mod component; -mod apresolve; + +pub mod apresolve; pub mod audio_key; pub mod authentication; pub mod cache; pub mod channel; pub mod config; -mod connection; +pub mod connection; pub mod diffie_hellman; pub mod keymaster; pub mod mercury; diff --git a/core/src/mercury/mod.rs b/core/src/mercury/mod.rs index 20e3f0db1..e77b4a45b 100644 --- a/core/src/mercury/mod.rs +++ b/core/src/mercury/mod.rs @@ -1,14 +1,14 @@ use crate::protocol; use crate::util::url_encode; +use crate::util::SeqGenerator; use byteorder::{BigEndian, ByteOrder}; use bytes::Bytes; -use futures::sync::{mpsc, oneshot}; -use futures::{Async, Future, Poll}; -use protobuf; -use std::collections::HashMap; -use std::mem; - -use crate::util::SeqGenerator; +use futures::{ + channel::{mpsc, oneshot}, + Future, +}; +use std::{collections::HashMap, task::Poll}; +use std::{mem, pin::Pin, task::Context}; mod types; pub use self::types::*; @@ -31,17 +31,17 @@ pub struct MercuryPending { callback: Option>>, } -pub struct MercuryFuture(oneshot::Receiver>); +#[pin_project] +pub struct MercuryFuture(#[pin] oneshot::Receiver>); + impl Future for MercuryFuture { - type Item = T; - type Error = MercuryError; - - fn poll(&mut self) -> Poll { - match self.0.poll() { - Ok(Async::Ready(Ok(value))) => Ok(Async::Ready(value)), - Ok(Async::Ready(Err(err))) => Err(err), - Ok(Async::NotReady) => Ok(Async::NotReady), - Err(oneshot::Canceled) => Err(MercuryError), + type Output = Result; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + match self.project().0.poll(cx) { + Poll::Ready(Ok(x)) => Poll::Ready(x), + Poll::Ready(Err(_)) => Poll::Ready(Err(MercuryError)), + Poll::Pending => Poll::Pending, } } } @@ -98,46 +98,46 @@ impl MercuryManager { MercurySender::new(self.clone(), uri.into()) } - pub fn subscribe>( + pub async fn subscribe>( &self, uri: T, - ) -> Box, Error = MercuryError>> - { + ) -> Result, MercuryError> { let uri = uri.into(); - let request = self.request(MercuryRequest { - method: MercuryMethod::SUB, - uri: uri.clone(), - content_type: None, - payload: Vec::new(), - }); + let response = self + .request(MercuryRequest { + method: MercuryMethod::SUB, + uri: uri.clone(), + content_type: None, + payload: Vec::new(), + }) + .await?; + + let (tx, rx) = mpsc::unbounded(); let manager = self.clone(); - Box::new(request.map(move |response| { - let (tx, rx) = mpsc::unbounded(); - - manager.lock(move |inner| { - if !inner.invalid { - debug!("subscribed uri={} count={}", uri, response.payload.len()); - if response.payload.len() > 0 { - // Old subscription protocol, watch the provided list of URIs - for sub in response.payload { - let mut sub: protocol::pubsub::Subscription = - protobuf::parse_from_bytes(&sub).unwrap(); - let sub_uri = sub.take_uri(); - - debug!("subscribed sub_uri={}", sub_uri); - - inner.subscriptions.push((sub_uri, tx.clone())); - } - } else { - // New subscription protocol, watch the requested URI - inner.subscriptions.push((uri, tx)); + + manager.lock(move |inner| { + if !inner.invalid { + debug!("subscribed uri={} count={}", uri, response.payload.len()); + if !response.payload.is_empty() { + // Old subscription protocol, watch the provided list of URIs + for sub in response.payload { + let mut sub: protocol::pubsub::Subscription = + protobuf::parse_from_bytes(&sub).unwrap(); + let sub_uri = sub.take_uri(); + + debug!("subscribed sub_uri={}", sub_uri); + + inner.subscriptions.push((sub_uri, tx.clone())); } + } else { + // New subscription protocol, watch the requested URI + inner.subscriptions.push((uri, tx)); } - }); + } + }); - rx - })) + Ok(rx) } pub(crate) fn dispatch(&self, cmd: u8, mut data: Bytes) { @@ -193,7 +193,7 @@ impl MercuryManager { let header: protocol::mercury::Header = protobuf::parse_from_bytes(&header_data).unwrap(); let response = MercuryResponse { - uri: url_encode(header.get_uri()).to_owned(), + uri: url_encode(header.get_uri()), status_code: header.get_status_code(), payload: pending.parts, }; diff --git a/core/src/mercury/sender.rs b/core/src/mercury/sender.rs index f00235ef9..860c2f335 100644 --- a/core/src/mercury/sender.rs +++ b/core/src/mercury/sender.rs @@ -1,5 +1,5 @@ -use futures::{Async, AsyncSink, Future, Poll, Sink, StartSend}; -use std::collections::VecDeque; +use futures::Sink; +use std::{collections::VecDeque, pin::Pin, task::Context}; use super::*; @@ -30,27 +30,38 @@ impl Clone for MercurySender { } } -impl Sink for MercurySender { - type SinkItem = Vec; - type SinkError = MercuryError; +impl Sink> for MercurySender { + type Error = MercuryError; - fn start_send(&mut self, item: Self::SinkItem) -> StartSend { - let task = self.mercury.send(self.uri.clone(), item); - self.pending.push_back(task); - Ok(AsyncSink::Ready) + fn poll_ready(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.poll_flush(cx) } - fn poll_complete(&mut self) -> Poll<(), Self::SinkError> { + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { loop { match self.pending.front_mut() { Some(task) => { - try_ready!(task.poll()); + match Pin::new(task).poll(cx) { + Poll::Ready(Err(x)) => return Poll::Ready(Err(x)), + Poll::Pending => return Poll::Pending, + _ => (), + }; } None => { - return Ok(Async::Ready(())); + return Poll::Ready(Ok(())); } } self.pending.pop_front(); } } + + fn start_send(mut self: Pin<&mut Self>, item: Vec) -> Result<(), Self::Error> { + let task = self.mercury.send(self.uri.clone(), item); + self.pending.push_back(task); + Ok(()) + } } diff --git a/core/src/proxytunnel.rs b/core/src/proxytunnel.rs index b13638469..508de7f80 100644 --- a/core/src/proxytunnel.rs +++ b/core/src/proxytunnel.rs @@ -1,110 +1,45 @@ use std::io; -use std::str::FromStr; -use futures::{Async, Future, Poll}; -use httparse; use hyper::Uri; -use tokio_io::io::{read, write_all, Read, Window, WriteAll}; -use tokio_io::{AsyncRead, AsyncWrite}; - -pub struct ProxyTunnel { - state: ProxyState, -} - -enum ProxyState { - ProxyConnect(WriteAll>), - ProxyResponse(Read>>), -} +use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; + +pub async fn connect( + mut connection: T, + connect_url: &str, +) -> io::Result { + let uri = connect_url.parse::().unwrap(); + let mut buffer = format!( + "CONNECT {0}:{1} HTTP/1.1\r\n\ + \r\n", + uri.host().unwrap_or_else(|| panic!("No host in {}", uri)), + uri.port().unwrap_or_else(|| panic!("No port in {}", uri)) + ) + .into_bytes(); + connection.write_all(buffer.as_ref()).await?; -pub fn connect(connection: T, connect_url: &str) -> ProxyTunnel { - let proxy = proxy_connect(connection, connect_url); - ProxyTunnel { - state: ProxyState::ProxyConnect(proxy), + buffer.clear(); + connection.read_to_end(&mut buffer).await?; + if buffer.is_empty() { + return Err(io::Error::new(io::ErrorKind::Other, "Early EOF from proxy")); } -} - -impl Future for ProxyTunnel { - type Item = T; - type Error = io::Error; - - fn poll(&mut self) -> Poll { - use self::ProxyState::*; - loop { - self.state = match self.state { - ProxyConnect(ref mut write) => { - let (connection, mut accumulator) = try_ready!(write.poll()); - - let capacity = accumulator.capacity(); - accumulator.resize(capacity, 0); - let window = Window::new(accumulator); - let read = read(connection, window); - ProxyResponse(read) - } + let mut headers = [httparse::EMPTY_HEADER; 16]; + let mut response = httparse::Response::new(&mut headers); - ProxyResponse(ref mut read_f) => { - let (connection, mut window, bytes_read) = try_ready!(read_f.poll()); + response + .parse(&buffer[..]) + .map_err(|err| io::Error::new(io::ErrorKind::Other, err.to_string()))?; - if bytes_read == 0 { - return Err(io::Error::new(io::ErrorKind::Other, "Early EOF from proxy")); - } - - let data_end = window.start() + bytes_read; - - let buf = window.get_ref()[0..data_end].to_vec(); - let mut headers = [httparse::EMPTY_HEADER; 16]; - let mut response = httparse::Response::new(&mut headers); - let status = match response.parse(&buf) { - Ok(status) => status, - Err(err) => { - return Err(io::Error::new(io::ErrorKind::Other, err.to_string())); - } - }; - - if status.is_complete() { - if let Some(code) = response.code { - if code == 200 { - // Proxy says all is well - return Ok(Async::Ready(connection)); - } else { - let reason = response.reason.unwrap_or("no reason"); - let msg = format!("Proxy responded with {}: {}", code, reason); - - return Err(io::Error::new(io::ErrorKind::Other, msg)); - } - } else { - return Err(io::Error::new( - io::ErrorKind::Other, - "Malformed response from proxy", - )); - } - } else { - if data_end >= window.end() { - // Allocate some more buffer space - let newsize = data_end + 100; - window.get_mut().resize(newsize, 0); - window.set_end(newsize); - } - // We did not get a full header - window.set_start(data_end); - let read = read(connection, window); - ProxyResponse(read) - } - } - } + match response.code { + Some(200) => Ok(connection), // Proxy says all is well + Some(code) => { + let reason = response.reason.unwrap_or("no reason"); + let msg = format!("Proxy responded with {}: {}", code, reason); + Err(io::Error::new(io::ErrorKind::Other, msg)) } + None => Err(io::Error::new( + io::ErrorKind::Other, + "Malformed response from proxy", + )), } } - -fn proxy_connect(connection: T, connect_url: &str) -> WriteAll> { - let uri = Uri::from_str(connect_url).unwrap(); - let buffer = format!( - "CONNECT {0}:{1} HTTP/1.1\r\n\ - \r\n", - uri.host().expect(&format!("No host in {}", uri)), - uri.port().expect(&format!("No port in {}", uri)) - ) - .into_bytes(); - - write_all(connection, buffer) -} diff --git a/core/src/session.rs b/core/src/session.rs index 4d86a02b7..2def40858 100644 --- a/core/src/session.rs +++ b/core/src/session.rs @@ -1,20 +1,20 @@ -use std::io; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, RwLock, Weak}; +use std::task::Poll; use std::time::{SystemTime, UNIX_EPOCH}; +use std::{io, pin::Pin, task::Context}; + +use once_cell::sync::OnceCell; use byteorder::{BigEndian, ByteOrder}; use bytes::Bytes; -use futures::sync::mpsc; -use futures::{Async, Future, IntoFuture, Poll, Stream}; -use tokio_core::reactor::{Handle, Remote}; +use futures::{channel::mpsc, Future, FutureExt, StreamExt, TryStream, TryStreamExt}; use crate::apresolve::apresolve_or_fallback; use crate::audio_key::AudioKeyManager; use crate::authentication::Credentials; use crate::cache::Cache; use crate::channel::ChannelManager; -use crate::component::Lazy; use crate::config::SessionConfig; use crate::connection; use crate::mercury::MercuryManager; @@ -32,13 +32,11 @@ struct SessionInternal { tx_connection: mpsc::UnboundedSender<(u8, Vec)>, - audio_key: Lazy, - channel: Lazy, - mercury: Lazy, + audio_key: OnceCell, + channel: OnceCell, + mercury: OnceCell, cache: Option>, - handle: Remote, - session_id: usize, } @@ -48,58 +46,34 @@ static SESSION_COUNTER: AtomicUsize = AtomicUsize::new(0); pub struct Session(Arc); impl Session { - pub fn connect( + pub async fn connect( config: SessionConfig, credentials: Credentials, cache: Option, - handle: Handle, - ) -> Box> { - let access_point = - apresolve_or_fallback::(&handle, &config.proxy, &config.ap_port); - - let handle_ = handle.clone(); - let proxy = config.proxy.clone(); - let connection = access_point.and_then(move |addr| { - info!("Connecting to AP \"{}\"", addr); - connection::connect(addr, &handle_, &proxy) - }); - - let device_id = config.device_id.clone(); - let authentication = connection.and_then(move |connection| { - connection::authenticate(connection, credentials, device_id) - }); - - let result = authentication.map(move |(transport, reusable_credentials)| { - info!("Authenticated as \"{}\" !", reusable_credentials.username); - if let Some(ref cache) = cache { - cache.save_credentials(&reusable_credentials); - } + ) -> io::Result { + let ap = apresolve_or_fallback(&config.proxy, &config.ap_port).await; - let (session, task) = Session::create( - &handle, - transport, - config, - cache, - reusable_credentials.username.clone(), - ); + info!("Connecting to AP \"{}\"", ap); + let mut conn = connection::connect(ap, &config.proxy).await?; - handle.spawn(task.map_err(|e| { - error!("{:?}", e); - })); + let reusable_credentials = + connection::authenticate(&mut conn, credentials, &config.device_id).await?; + info!("Authenticated as \"{}\" !", reusable_credentials.username); + if let Some(cache) = &cache { + cache.save_credentials(&reusable_credentials); + } - session - }); + let session = Session::create(conn, config, cache, reusable_credentials.username); - Box::new(result) + Ok(session) } fn create( - handle: &Handle, transport: connection::Transport, config: SessionConfig, cache: Option, username: String, - ) -> (Session, Box>) { + ) -> Session { let (sink, stream) = transport.split(); let (sender_tx, sender_rx) = mpsc::unbounded(); @@ -120,53 +94,50 @@ impl Session { cache: cache.map(Arc::new), - audio_key: Lazy::new(), - channel: Lazy::new(), - mercury: Lazy::new(), - - handle: handle.remote().clone(), + audio_key: OnceCell::new(), + channel: OnceCell::new(), + mercury: OnceCell::new(), session_id: session_id, })); - let sender_task = sender_rx - .map_err(|e| -> io::Error { panic!(e) }) - .forward(sink) - .map(|_| ()); + let sender_task = sender_rx.map(Ok::<_, io::Error>).forward(sink); let receiver_task = DispatchTask(stream, session.weak()); - let task = Box::new( - (receiver_task, sender_task) - .into_future() - .map(|((), ())| ()), - ); - - (session, task) + let task = + futures::future::join(sender_task, receiver_task).map(|_| io::Result::<_>::Ok(())); + tokio::spawn(task); + session } pub fn audio_key(&self) -> &AudioKeyManager { - self.0.audio_key.get(|| AudioKeyManager::new(self.weak())) + self.0 + .audio_key + .get_or_init(|| AudioKeyManager::new(self.weak())) } pub fn channel(&self) -> &ChannelManager { - self.0.channel.get(|| ChannelManager::new(self.weak())) + self.0 + .channel + .get_or_init(|| ChannelManager::new(self.weak())) } pub fn mercury(&self) -> &MercuryManager { - self.0.mercury.get(|| MercuryManager::new(self.weak())) + self.0 + .mercury + .get_or_init(|| MercuryManager::new(self.weak())) } pub fn time_delta(&self) -> i64 { self.0.data.read().unwrap().time_delta } - pub fn spawn(&self, f: F) + pub fn spawn(&self, task: T) where - F: FnOnce(&Handle) -> R + Send + 'static, - R: IntoFuture, - R::Future: 'static, + T: Future + Send + 'static, + T::Output: Send + 'static, { - self.0.handle.spawn(f) + tokio::spawn(task); } fn debug_info(&self) { @@ -178,7 +149,7 @@ impl Session { ); } - #[cfg_attr(feature = "cargo-clippy", allow(match_same_arms))] + #[allow(clippy::match_same_arms)] fn dispatch(&self, cmd: u8, data: Bytes) { match cmd { 0x4 => { @@ -273,35 +244,34 @@ impl Drop for SessionInternal { struct DispatchTask(S, SessionWeak) where - S: Stream; + S: TryStream + Unpin; impl Future for DispatchTask where - S: Stream, - ::Error: ::std::fmt::Debug, + S: TryStream + Unpin, + ::Ok: std::fmt::Debug, { - type Item = (); - type Error = S::Error; + type Output = Result<(), S::Error>; - fn poll(&mut self) -> Poll { + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let session = match self.1.try_upgrade() { Some(session) => session, - None => return Ok(Async::Ready(())), + None => return Poll::Ready(Ok(())), }; loop { - let (cmd, data) = match self.0.poll() { - Ok(Async::Ready(Some(t))) => t, - Ok(Async::Ready(None)) => { + let (cmd, data) = match self.0.try_poll_next_unpin(cx) { + Poll::Ready(Some(Ok(t))) => t, + Poll::Ready(None) => { warn!("Connection to server closed."); session.shutdown(); - return Ok(Async::Ready(())); + return Poll::Ready(Ok(())); } - Ok(Async::NotReady) => return Ok(Async::NotReady), - Err(e) => { + Poll::Ready(Some(Err(e))) => { session.shutdown(); - return Err(From::from(e)); + return Poll::Ready(Err(e)); } + Poll::Pending => return Poll::Pending, }; session.dispatch(cmd, data); @@ -311,7 +281,7 @@ where impl Drop for DispatchTask where - S: Stream, + S: TryStream + Unpin, { fn drop(&mut self) { debug!("drop Dispatch"); From 6867ad0750d6be9e95d3e11f38d09cc53a38c3d3 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Thu, 21 Jan 2021 21:56:23 +0100 Subject: [PATCH 13/75] Added test --- core/tests/connect.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 core/tests/connect.rs diff --git a/core/tests/connect.rs b/core/tests/connect.rs new file mode 100644 index 000000000..44d418a1f --- /dev/null +++ b/core/tests/connect.rs @@ -0,0 +1,32 @@ +use librespot_core::*; + +#[cfg(test)] +mod tests { + use super::*; + // Test AP Resolve + use apresolve::apresolve_or_fallback; + #[tokio::test] + async fn test_ap_resolve() { + let ap = apresolve_or_fallback(&None, &None).await; + println!("AP: {:?}", ap); + } + + // Test connect + use authentication::Credentials; + use config::SessionConfig; + #[tokio::test] + async fn test_connection() -> Result<(), Box> { + println!("Running connection test"); + let ap = apresolve_or_fallback(&None, &None).await; + let credentials = Credentials::with_password(String::from("test"), String::from("test")); + let session_config = SessionConfig::default(); + let proxy = None; + + println!("Connecting to AP \"{}\"", ap); + let mut connection = connection::connect(ap, &proxy).await?; + let rc = connection::authenticate(&mut connection, credentials, &session_config.device_id) + .await?; + println!("Authenticated as \"{}\"", rc.username); + Ok(()) + } +} From 424ba3ae2596854514767c824ac2a24d5abb355d Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Thu, 21 Jan 2021 22:07:16 +0100 Subject: [PATCH 14/75] Migrated metadata crate to futures 0.3 --- metadata/Cargo.toml | 3 +- metadata/src/lib.rs | 97 ++++++++++++++++++++------------------------- 2 files changed, 45 insertions(+), 55 deletions(-) diff --git a/metadata/Cargo.toml b/metadata/Cargo.toml index 8f3b4c932..f5e612372 100644 --- a/metadata/Cargo.toml +++ b/metadata/Cargo.toml @@ -8,8 +8,9 @@ repository = "https://github.com/librespot-org/librespot" edition = "2018" [dependencies] +async-trait = "0.1" byteorder = "1.3" -futures = "0.1" +futures = "0.3" linear-map = "1.2" protobuf = "~2.14.0" log = "0.4" diff --git a/metadata/src/lib.rs b/metadata/src/lib.rs index 8bd422ce5..f71bae95d 100644 --- a/metadata/src/lib.rs +++ b/metadata/src/lib.rs @@ -1,6 +1,11 @@ +#![allow(clippy::unused_io_amount)] +#![allow(clippy::redundant_field_names)] #[macro_use] extern crate log; +#[macro_use] +extern crate async_trait; + extern crate byteorder; extern crate futures; extern crate linear_map; @@ -11,8 +16,6 @@ extern crate librespot_protocol as protocol; pub mod cover; -use futures::future; -use futures::Future; use linear_map::LinearMap; use librespot_core::mercury::MercuryError; @@ -69,81 +72,67 @@ pub struct AudioItem { } impl AudioItem { - pub fn get_audio_item( - session: &Session, - id: SpotifyId, - ) -> Box> { + pub async fn get_audio_item(session: &Session, id: SpotifyId) -> Result { match id.audio_type { - SpotifyAudioType::Track => Track::get_audio_item(session, id), - SpotifyAudioType::Podcast => Episode::get_audio_item(session, id), - SpotifyAudioType::NonPlayable => { - Box::new(future::err::(MercuryError)) - } + SpotifyAudioType::Track => Track::get_audio_item(session, id).await, + SpotifyAudioType::Podcast => Episode::get_audio_item(session, id).await, + SpotifyAudioType::NonPlayable => Err(MercuryError), } } } +#[async_trait] trait AudioFiles { - fn get_audio_item( - session: &Session, - id: SpotifyId, - ) -> Box>; + async fn get_audio_item(session: &Session, id: SpotifyId) -> Result; } +#[async_trait] impl AudioFiles for Track { - fn get_audio_item( - session: &Session, - id: SpotifyId, - ) -> Box> { - Box::new(Self::get(session, id).and_then(move |item| { - Ok(AudioItem { - id: id, - uri: format!("spotify:track:{}", id.to_base62()), - files: item.files, - name: item.name, - duration: item.duration, - available: item.available, - alternatives: Some(item.alternatives), - }) - })) + async fn get_audio_item(session: &Session, id: SpotifyId) -> Result { + let item = Self::get(session, id).await?; + Ok(AudioItem { + id: id, + uri: format!("spotify:track:{}", id.to_base62()), + files: item.files, + name: item.name, + duration: item.duration, + available: item.available, + alternatives: Some(item.alternatives), + }) } } +#[async_trait] impl AudioFiles for Episode { - fn get_audio_item( - session: &Session, - id: SpotifyId, - ) -> Box> { - Box::new(Self::get(session, id).and_then(move |item| { - Ok(AudioItem { - id: id, - uri: format!("spotify:episode:{}", id.to_base62()), - files: item.files, - name: item.name, - duration: item.duration, - available: item.available, - alternatives: None, - }) - })) + async fn get_audio_item(session: &Session, id: SpotifyId) -> Result { + let item = Self::get(session, id).await?; + + Ok(AudioItem { + id: id, + uri: format!("spotify:episode:{}", id.to_base62()), + files: item.files, + name: item.name, + duration: item.duration, + available: item.available, + alternatives: None, + }) } } + +#[async_trait] pub trait Metadata: Send + Sized + 'static { type Message: protobuf::Message; fn request_url(id: SpotifyId) -> String; fn parse(msg: &Self::Message, session: &Session) -> Self; - fn get(session: &Session, id: SpotifyId) -> Box> { + async fn get(session: &Session, id: SpotifyId) -> Result { let uri = Self::request_url(id); - let request = session.mercury().get(uri); - - let session = session.clone(); - Box::new(request.and_then(move |response| { - let data = response.payload.first().expect("Empty payload"); - let msg: Self::Message = protobuf::parse_from_bytes(data).unwrap(); + let response = session.mercury().get(uri).await?; + let data = response.payload.first().expect("Empty payload"); + let msg: Self::Message = protobuf::parse_from_bytes(data).unwrap(); - Ok(Self::parse(&msg, &session)) - })) + Ok(Self::parse(&msg, &session)) } } From 80d384e00164b61f4ef9c52acee345300e091341 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Thu, 21 Jan 2021 22:12:35 +0100 Subject: [PATCH 15/75] Migrated audio crate to futures 0.3 --- audio/Cargo.toml | 9 +- audio/src/decrypt.rs | 4 +- audio/src/fetch.rs | 759 +++++++++++++++++++++++-------------------- audio/src/lib.rs | 7 +- 4 files changed, 415 insertions(+), 364 deletions(-) diff --git a/audio/Cargo.toml b/audio/Cargo.toml index cde907c1a..f9d232b37 100644 --- a/audio/Cargo.toml +++ b/audio/Cargo.toml @@ -11,16 +11,17 @@ path = "../core" version = "0.1.3" [dependencies] +aes-ctr = "0.6" bit-set = "0.5" -byteorder = "1.3" -bytes = "0.4" -futures = "0.1" +byteorder = "1.4" +bytes = "1.0" +futures = "0.3" lewton = "0.9" log = "0.4" num-bigint = "0.3" num-traits = "0.2" +pin-project = "1.0" tempfile = "3.1" -aes-ctr = "0.3" librespot-tremor = { version = "0.1.0", optional = true } vorbis = { version ="0.0.14", optional = true } diff --git a/audio/src/decrypt.rs b/audio/src/decrypt.rs index 818eb34e2..616ef4f68 100644 --- a/audio/src/decrypt.rs +++ b/audio/src/decrypt.rs @@ -1,7 +1,7 @@ use std::io; -use aes_ctr::stream_cipher::generic_array::GenericArray; -use aes_ctr::stream_cipher::{NewStreamCipher, SyncStreamCipher, SyncStreamCipherSeek}; +use aes_ctr::cipher::generic_array::GenericArray; +use aes_ctr::cipher::{NewStreamCipher, SyncStreamCipher, SyncStreamCipherSeek}; use aes_ctr::Aes128Ctr; use librespot_core::audio_key::AudioKey; diff --git a/audio/src/fetch.rs b/audio/src/fetch.rs index c47cb4d3b..5d15866c6 100644 --- a/audio/src/fetch.rs +++ b/audio/src/fetch.rs @@ -1,17 +1,25 @@ use crate::range_set::{Range, RangeSet}; use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; use bytes::Bytes; -use futures::sync::{mpsc, oneshot}; -use futures::Stream; -use futures::{Async, Future, Poll}; -use std::cmp::{max, min}; +use futures::{ + channel::{mpsc, oneshot}, + future, +}; +use futures::{Future, Stream, StreamExt, TryFutureExt, TryStreamExt}; + use std::fs; use std::io::{self, Read, Seek, SeekFrom, Write}; use std::sync::{Arc, Condvar, Mutex}; +use std::task::Poll; use std::time::{Duration, Instant}; +use std::{ + cmp::{max, min}, + pin::Pin, + task::Context, +}; use tempfile::NamedTempFile; -use futures::sync::mpsc::unbounded; +use futures::channel::mpsc::unbounded; use librespot_core::channel::{Channel, ChannelData, ChannelError, ChannelHeaders}; use librespot_core::session::Session; use librespot_core::spotify_id::FileId; @@ -88,22 +96,6 @@ pub enum AudioFile { Streaming(AudioFileStreaming), } -pub enum AudioFileOpen { - Cached(Option), - Streaming(AudioFileOpenStreaming), -} - -pub struct AudioFileOpenStreaming { - session: Session, - initial_data_rx: Option, - initial_data_length: Option, - initial_request_sent_time: Instant, - headers: ChannelHeaders, - file_id: FileId, - complete_tx: Option>, - streaming_data_rate: usize, -} - enum StreamLoaderCommand { Fetch(Range), // signal the stream loader to fetch a range of the file RandomAccessMode(), // optimise download strategy for random access @@ -120,45 +112,36 @@ pub struct StreamLoaderController { impl StreamLoaderController { pub fn len(&self) -> usize { - return self.file_size; + self.file_size + } + + pub fn is_empty(&self) -> bool { + self.file_size == 0 } pub fn range_available(&self, range: Range) -> bool { if let Some(ref shared) = self.stream_shared { let download_status = shared.download_status.lock().unwrap(); - if range.length + range.length <= download_status .downloaded .contained_length_from_value(range.start) - { - return true; - } else { - return false; - } } else { - if range.length <= self.len() - range.start { - return true; - } else { - return false; - } + range.length <= self.len() - range.start } } pub fn range_to_end_available(&self) -> bool { - if let Some(ref shared) = self.stream_shared { + self.stream_shared.as_ref().map_or(true, |shared| { let read_position = shared.read_position.load(atomic::Ordering::Relaxed); self.range_available(Range::new(read_position, self.len() - read_position)) - } else { - true - } + }) } pub fn ping_time_ms(&self) -> usize { - if let Some(ref shared) = self.stream_shared { - return shared.ping_time_ms.load(atomic::Ordering::Relaxed); - } else { - return 0; - } + self.stream_shared.as_ref().map_or(0, |shared| { + shared.ping_time_ms.load(atomic::Ordering::Relaxed) + }) } fn send_stream_loader_command(&mut self, command: StreamLoaderCommand) { @@ -216,27 +199,23 @@ impl StreamLoaderController { } pub fn fetch_next(&mut self, length: usize) { - let range: Range = if let Some(ref shared) = self.stream_shared { - Range { + if let Some(ref shared) = self.stream_shared { + let range = Range { start: shared.read_position.load(atomic::Ordering::Relaxed), length: length, - } - } else { - return; - }; - self.fetch(range); + }; + self.fetch(range) + } } pub fn fetch_next_blocking(&mut self, length: usize) { - let range: Range = if let Some(ref shared) = self.stream_shared { - Range { + if let Some(ref shared) = self.stream_shared { + let range = Range { start: shared.read_position.load(atomic::Ordering::Relaxed), length: length, - } - } else { - return; - }; - self.fetch_blocking(range); + }; + self.fetch_blocking(range); + } } pub fn set_random_access_mode(&mut self) { @@ -288,12 +267,100 @@ struct AudioFileShared { read_position: AtomicUsize, } -impl AudioFileOpenStreaming { - fn finish(&mut self, size: usize) -> AudioFileStreaming { +impl AudioFile { + pub async fn open( + session: &Session, + file_id: FileId, + bytes_per_second: usize, + play_from_beginning: bool, + ) -> Result { + if let Some(file) = session.cache().and_then(|cache| cache.file(file_id)) { + debug!("File {} already in cache", file_id); + return Ok(AudioFile::Cached(file)); + } + + debug!("Downloading file {}", file_id); + + let (complete_tx, complete_rx) = oneshot::channel(); + let mut initial_data_length = if play_from_beginning { + INITIAL_DOWNLOAD_SIZE + + max( + (READ_AHEAD_DURING_PLAYBACK_SECONDS * bytes_per_second as f64) as usize, + (INITIAL_PING_TIME_ESTIMATE_SECONDS + * READ_AHEAD_DURING_PLAYBACK_ROUNDTRIPS + * bytes_per_second as f64) as usize, + ) + } else { + INITIAL_DOWNLOAD_SIZE + }; + if initial_data_length % 4 != 0 { + initial_data_length += 4 - (initial_data_length % 4); + } + let (headers, data) = request_range(session, file_id, 0, initial_data_length).split(); + + let streaming = AudioFileStreaming::open( + session.clone(), + data, + initial_data_length, + Instant::now(), + headers, + file_id, + complete_tx, + bytes_per_second, + ); + + let session_ = session.clone(); + session.spawn(complete_rx.map_ok(move |mut file| { + if let Some(cache) = session_.cache() { + cache.save_file(file_id, &mut file); + debug!("File {} complete, saving to cache", file_id); + } else { + debug!("File {} complete", file_id); + } + })); + + Ok(AudioFile::Streaming(streaming.await?)) + } + + pub fn get_stream_loader_controller(&self) -> StreamLoaderController { + match self { + AudioFile::Streaming(ref stream) => StreamLoaderController { + channel_tx: Some(stream.stream_loader_command_tx.clone()), + stream_shared: Some(stream.shared.clone()), + file_size: stream.shared.file_size, + }, + AudioFile::Cached(ref file) => StreamLoaderController { + channel_tx: None, + stream_shared: None, + file_size: file.metadata().unwrap().len() as usize, + }, + } + } +} + +impl AudioFileStreaming { + pub async fn open( + session: Session, + initial_data_rx: ChannelData, + initial_data_length: usize, + initial_request_sent_time: Instant, + headers: ChannelHeaders, + file_id: FileId, + complete_tx: oneshot::Sender, + streaming_data_rate: usize, + ) -> Result { + let (_, data) = headers + .try_filter(|(id, _)| future::ready(*id == 0x3)) + .next() + .await + .unwrap()?; + + let size = BigEndian::read_u32(&data) as usize * 4; + let shared = Arc::new(AudioFileShared { - file_id: self.file_id, + file_id: file_id, file_size: size, - stream_data_rate: self.streaming_data_rate, + stream_data_rate: streaming_data_rate, cond: Condvar::new(), download_status: Mutex::new(AudioFileDownloadStatus { requested: RangeSet::new(), @@ -311,153 +378,29 @@ impl AudioFileOpenStreaming { let read_file = write_file.reopen().unwrap(); - let initial_data_rx = self.initial_data_rx.take().unwrap(); - let initial_data_length = self.initial_data_length.take().unwrap(); - let complete_tx = self.complete_tx.take().unwrap(); //let (seek_tx, seek_rx) = mpsc::unbounded(); let (stream_loader_command_tx, stream_loader_command_rx) = mpsc::unbounded::(); let fetcher = AudioFileFetch::new( - self.session.clone(), + session.clone(), shared.clone(), initial_data_rx, - self.initial_request_sent_time, + initial_request_sent_time, initial_data_length, write_file, stream_loader_command_rx, complete_tx, ); - self.session.spawn(move |_| fetcher); - AudioFileStreaming { + session.spawn(fetcher); + Ok(AudioFileStreaming { read_file: read_file, - position: 0, //seek: seek_tx, stream_loader_command_tx: stream_loader_command_tx, - shared: shared, - } - } -} - -impl Future for AudioFileOpen { - type Item = AudioFile; - type Error = ChannelError; - - fn poll(&mut self) -> Poll { - match *self { - AudioFileOpen::Streaming(ref mut open) => { - let file = try_ready!(open.poll()); - Ok(Async::Ready(AudioFile::Streaming(file))) - } - AudioFileOpen::Cached(ref mut file) => { - let file = file.take().unwrap(); - Ok(Async::Ready(AudioFile::Cached(file))) - } - } - } -} - -impl Future for AudioFileOpenStreaming { - type Item = AudioFileStreaming; - type Error = ChannelError; - - fn poll(&mut self) -> Poll { - loop { - let (id, data) = try_ready!(self.headers.poll()).unwrap(); - - if id == 0x3 { - let size = BigEndian::read_u32(&data) as usize * 4; - let file = self.finish(size); - - return Ok(Async::Ready(file)); - } - } - } -} - -impl AudioFile { - pub fn open( - session: &Session, - file_id: FileId, - bytes_per_second: usize, - play_from_beginning: bool, - ) -> AudioFileOpen { - let cache = session.cache().cloned(); - - if let Some(file) = cache.as_ref().and_then(|cache| cache.file(file_id)) { - debug!("File {} already in cache", file_id); - return AudioFileOpen::Cached(Some(file)); - } - - debug!("Downloading file {}", file_id); - - let (complete_tx, complete_rx) = oneshot::channel(); - let mut initial_data_length = if play_from_beginning { - INITIAL_DOWNLOAD_SIZE - + max( - (READ_AHEAD_DURING_PLAYBACK_SECONDS * bytes_per_second as f64) as usize, - (INITIAL_PING_TIME_ESTIMATE_SECONDS - * READ_AHEAD_DURING_PLAYBACK_ROUNDTRIPS - * bytes_per_second as f64) as usize, - ) - } else { - INITIAL_DOWNLOAD_SIZE - }; - if initial_data_length % 4 != 0 { - initial_data_length += 4 - (initial_data_length % 4); - } - let (headers, data) = request_range(session, file_id, 0, initial_data_length).split(); - - let open = AudioFileOpenStreaming { - session: session.clone(), - file_id: file_id, - - headers: headers, - initial_data_rx: Some(data), - initial_data_length: Some(initial_data_length), - initial_request_sent_time: Instant::now(), - - complete_tx: Some(complete_tx), - streaming_data_rate: bytes_per_second, - }; - - let session_ = session.clone(); - session.spawn(move |_| { - complete_rx - .map(move |mut file| { - if let Some(cache) = session_.cache() { - cache.save_file(file_id, &mut file); - debug!("File {} complete, saving to cache", file_id); - } else { - debug!("File {} complete", file_id); - } - }) - .or_else(|oneshot::Canceled| Ok(())) - }); - - return AudioFileOpen::Streaming(open); - } - - pub fn get_stream_loader_controller(&self) -> StreamLoaderController { - match self { - AudioFile::Streaming(ref stream) => { - return StreamLoaderController { - channel_tx: Some(stream.stream_loader_command_tx.clone()), - stream_shared: Some(stream.shared.clone()), - file_size: stream.shared.file_size, - }; - } - AudioFile::Cached(ref file) => { - return StreamLoaderController { - channel_tx: None, - stream_shared: None, - file_size: file.metadata().unwrap().len() as usize, - }; - } - } + }) } } @@ -502,141 +445,261 @@ enum ReceivedData { Data(PartialFileData), } -struct AudioFileFetchDataReceiver { +async fn audio_file_fetch_receive_data( shared: Arc, file_data_tx: mpsc::UnboundedSender, data_rx: ChannelData, initial_data_offset: usize, initial_request_length: usize, - data_offset: usize, - request_length: usize, - request_sent_time: Option, - measure_ping_time: bool, -} - -impl AudioFileFetchDataReceiver { - fn new( - shared: Arc, - file_data_tx: mpsc::UnboundedSender, - data_rx: ChannelData, - data_offset: usize, - request_length: usize, - request_sent_time: Instant, - ) -> AudioFileFetchDataReceiver { - let measure_ping_time = shared - .number_of_open_requests - .load(atomic::Ordering::SeqCst) - == 0; - - shared - .number_of_open_requests - .fetch_add(1, atomic::Ordering::SeqCst); - - AudioFileFetchDataReceiver { - shared: shared, - data_rx: data_rx, - file_data_tx: file_data_tx, - initial_data_offset: data_offset, - initial_request_length: request_length, - data_offset: data_offset, - request_length: request_length, - request_sent_time: Some(request_sent_time), - measure_ping_time: measure_ping_time, - } + request_sent_time: Instant, +) { + let mut data_offset = initial_data_offset; + let mut request_length = initial_request_length; + let mut measure_ping_time = shared + .number_of_open_requests + .load(atomic::Ordering::SeqCst) + == 0; + + shared + .number_of_open_requests + .fetch_add(1, atomic::Ordering::SeqCst); + + enum TryFoldErr { + ChannelError, + FinishEarly, } -} -impl AudioFileFetchDataReceiver { - fn finish(&mut self) { - if self.request_length > 0 { - let missing_range = Range::new(self.data_offset, self.request_length); + let result = data_rx + .map_err(|_| TryFoldErr::ChannelError) + .try_for_each(|data| { + if measure_ping_time { + let duration = Instant::now() - request_sent_time; + let duration_ms: u64; + if 0.001 * (duration.as_millis() as f64) + > MAXIMUM_ASSUMED_PING_TIME_SECONDS + { + duration_ms = (MAXIMUM_ASSUMED_PING_TIME_SECONDS * 1000.0) as u64; + } else { + duration_ms = duration.as_millis() as u64; + } + let _ = file_data_tx + .unbounded_send(ReceivedData::ResponseTimeMs(duration_ms as usize)); + measure_ping_time = false; + } + let data_size = data.len(); + let _ = file_data_tx + .unbounded_send(ReceivedData::Data(PartialFileData { + offset: data_offset, + data: data, + })); + data_offset += data_size; + if request_length < data_size { + warn!("Data receiver for range {} (+{}) received more data from server than requested.", initial_data_offset, initial_request_length); + request_length = 0; + } else { + request_length -= data_size; + } - let mut download_status = self.shared.download_status.lock().unwrap(); - download_status.requested.subtract_range(&missing_range); - self.shared.cond.notify_all(); - } + future::ready(if request_length == 0 { + Err(TryFoldErr::FinishEarly) + } else { + Ok(()) + }) + }) + .await; - self.shared - .number_of_open_requests - .fetch_sub(1, atomic::Ordering::SeqCst); + if request_length > 0 { + let missing_range = Range::new(data_offset, request_length); + + let mut download_status = shared.download_status.lock().unwrap(); + download_status.requested.subtract_range(&missing_range); + shared.cond.notify_all(); + } + + shared + .number_of_open_requests + .fetch_sub(1, atomic::Ordering::SeqCst); + + if let Err(TryFoldErr::ChannelError) = result { + warn!( + "Error from channel for data receiver for range {} (+{}).", + initial_data_offset, initial_request_length + ); + } else if request_length > 0 { + warn!( + "Data receiver for range {} (+{}) received less data from server than requested.", + initial_data_offset, initial_request_length + ); } } +/* +async fn audio_file_fetch( + session: Session, + shared: Arc, + initial_data_rx: ChannelData, + initial_request_sent_time: Instant, + initial_data_length: usize, -impl Future for AudioFileFetchDataReceiver { - type Item = (); - type Error = (); + output: NamedTempFile, + stream_loader_command_rx: mpsc::UnboundedReceiver, + complete_tx: oneshot::Sender, +) { + let (file_data_tx, file_data_rx) = unbounded::(); + + let requested_range = Range::new(0, initial_data_length); + let mut download_status = shared.download_status.lock().unwrap(); + download_status.requested.add_range(&requested_range); + + session.spawn(audio_file_fetch_receive_data( + shared.clone(), + file_data_tx.clone(), + initial_data_rx, + 0, + initial_data_length, + initial_request_sent_time, + )); + + let mut network_response_times_ms: Vec::new(); + + let f1 = file_data_rx.map(|x| Ok::<_, ()>(x)).try_for_each(|x| { + match x { + ReceivedData::ResponseTimeMs(response_time_ms) => { + trace!("Ping time estimated as: {} ms.", response_time_ms); + + // record the response time + network_response_times_ms.push(response_time_ms); + + // prune old response times. Keep at most three. + while network_response_times_ms.len() > 3 { + network_response_times_ms.remove(0); + } - fn poll(&mut self) -> Poll<(), ()> { - loop { - match self.data_rx.poll() { - Ok(Async::Ready(Some(data))) => { - if self.measure_ping_time { - if let Some(request_sent_time) = self.request_sent_time { - let duration = Instant::now() - request_sent_time; - let duration_ms: u64; - if 0.001 * (duration.as_millis() as f64) - > MAXIMUM_ASSUMED_PING_TIME_SECONDS - { - duration_ms = (MAXIMUM_ASSUMED_PING_TIME_SECONDS * 1000.0) as u64; - } else { - duration_ms = duration.as_millis() as u64; - } - let _ = self - .file_data_tx - .unbounded_send(ReceivedData::ResponseTimeMs(duration_ms as usize)); - self.measure_ping_time = false; - } + // stats::median is experimental. So we calculate the median of up to three ourselves. + let ping_time_ms: usize = match network_response_times_ms.len() { + 1 => network_response_times_ms[0] as usize, + 2 => { + ((network_response_times_ms[0] + network_response_times_ms[1]) / 2) as usize } - let data_size = data.len(); - let _ = self - .file_data_tx - .unbounded_send(ReceivedData::Data(PartialFileData { - offset: self.data_offset, - data: data, - })); - self.data_offset += data_size; - if self.request_length < data_size { - warn!("Data receiver for range {} (+{}) received more data from server than requested.", self.initial_data_offset, self.initial_request_length); - self.request_length = 0; - } else { - self.request_length -= data_size; + 3 => { + let mut times = network_response_times_ms.clone(); + times.sort(); + times[1] } - if self.request_length == 0 { - self.finish(); - return Ok(Async::Ready(())); + _ => unreachable!(), + }; + + // store our new estimate for everyone to see + shared + .ping_time_ms + .store(ping_time_ms, atomic::Ordering::Relaxed); + } + ReceivedData::Data(data) => { + output + .as_mut() + .unwrap() + .seek(SeekFrom::Start(data.offset as u64)) + .unwrap(); + output + .as_mut() + .unwrap() + .write_all(data.data.as_ref()) + .unwrap(); + + let mut full = false; + + { + let mut download_status = shared.download_status.lock().unwrap(); + + let received_range = Range::new(data.offset, data.data.len()); + download_status.downloaded.add_range(&received_range); + shared.cond.notify_all(); + + if download_status.downloaded.contained_length_from_value(0) + >= shared.file_size + { + full = true; } + + drop(download_status); } - Ok(Async::Ready(None)) => { - if self.request_length > 0 { - warn!("Data receiver for range {} (+{}) received less data from server than requested.", self.initial_data_offset, self.initial_request_length); - } + + if full { self.finish(); - return Ok(Async::Ready(())); + return future::ready(Err(())); } - Ok(Async::NotReady) => { - return Ok(Async::NotReady); - } - Err(ChannelError) => { - warn!( - "Error from channel for data receiver for range {} (+{}).", - self.initial_data_offset, self.initial_request_length + } + } + future::ready(Ok(())) + }); + + let f2 = stream_loader_command_rx.map(Ok::<_, ()>).try_for_each(|x| { + match cmd { + StreamLoaderCommand::Fetch(request) => { + self.download_range(request.start, request.length); + } + StreamLoaderCommand::RandomAccessMode() => { + *(shared.download_strategy.lock().unwrap()) = DownloadStrategy::RandomAccess(); + } + StreamLoaderCommand::StreamMode() => { + *(shared.download_strategy.lock().unwrap()) = DownloadStrategy::Streaming(); + } + StreamLoaderCommand::Close() => return future::ready(Err(())), + } + Ok(()) + }); + + let f3 = future::poll_fn(|_| { + if let DownloadStrategy::Streaming() = self.get_download_strategy() { + let number_of_open_requests = shared + .number_of_open_requests + .load(atomic::Ordering::SeqCst); + let max_requests_to_send = + MAX_PREFETCH_REQUESTS - min(MAX_PREFETCH_REQUESTS, number_of_open_requests); + + if max_requests_to_send > 0 { + let bytes_pending: usize = { + let download_status = shared.download_status.lock().unwrap(); + download_status + .requested + .minus(&download_status.downloaded) + .len() + }; + + let ping_time_seconds = + 0.001 * shared.ping_time_ms.load(atomic::Ordering::Relaxed) as f64; + let download_rate = session.channel().get_download_rate_estimate(); + + let desired_pending_bytes = max( + (PREFETCH_THRESHOLD_FACTOR * ping_time_seconds * shared.stream_data_rate as f64) + as usize, + (FAST_PREFETCH_THRESHOLD_FACTOR * ping_time_seconds * download_rate as f64) + as usize, + ); + + if bytes_pending < desired_pending_bytes { + self.pre_fetch_more_data( + desired_pending_bytes - bytes_pending, + max_requests_to_send, ); - self.finish(); - return Ok(Async::Ready(())); } } } - } -} + Poll::Pending + }); + future::select_all(vec![f1, f2, f3]).await +}*/ +#[pin_project] struct AudioFileFetch { session: Session, shared: Arc, output: Option, file_data_tx: mpsc::UnboundedSender, + #[pin] file_data_rx: mpsc::UnboundedReceiver, + #[pin] stream_loader_command_rx: mpsc::UnboundedReceiver, complete_tx: Option>, network_response_times_ms: Vec, @@ -662,16 +725,14 @@ impl AudioFileFetch { download_status.requested.add_range(&requested_range); } - let initial_data_receiver = AudioFileFetchDataReceiver::new( + session.spawn(audio_file_fetch_receive_data( shared.clone(), file_data_tx.clone(), initial_data_rx, 0, initial_data_length, initial_request_sent_time, - ); - - session.spawn(move |_| initial_data_receiver); + )); AudioFileFetch { session: session, @@ -701,7 +762,7 @@ impl AudioFileFetch { return; } - if length <= 0 { + if length == 0 { return; } @@ -737,16 +798,14 @@ impl AudioFileFetch { download_status.requested.add_range(range); - let receiver = AudioFileFetchDataReceiver::new( + self.session.spawn(audio_file_fetch_receive_data( self.shared.clone(), self.file_data_tx.clone(), data, range.start, range.length, Instant::now(), - ); - - self.session.spawn(move |_| receiver); + )); } } @@ -794,13 +853,13 @@ impl AudioFileFetch { } } - fn poll_file_data_rx(&mut self) -> Poll<(), ()> { + + + fn poll_file_data_rx(&mut self, cx: &mut Context<'_>) -> Poll<()> { loop { - match self.file_data_rx.poll() { - Ok(Async::Ready(None)) => { - return Ok(Async::Ready(())); - } - Ok(Async::Ready(Some(ReceivedData::ResponseTimeMs(response_time_ms)))) => { + match Pin::new(&mut self.file_data_rx).poll_next(cx) { + Poll::Ready(None) => return Poll::Ready(()), + Poll::Ready(Some(ReceivedData::ResponseTimeMs(response_time_ms))) => { trace!("Ping time estimated as: {} ms.", response_time_ms); // record the response time @@ -821,7 +880,7 @@ impl AudioFileFetch { } 3 => { let mut times = self.network_response_times_ms.clone(); - times.sort(); + times.sort_unstable(); times[1] } _ => unreachable!(), @@ -832,7 +891,7 @@ impl AudioFileFetch { .ping_time_ms .store(ping_time_ms, atomic::Ordering::Relaxed); } - Ok(Async::Ready(Some(ReceivedData::Data(data)))) => { + Poll::Ready(Some(ReceivedData::Data(data))) => { self.output .as_mut() .unwrap() @@ -864,39 +923,40 @@ impl AudioFileFetch { if full { self.finish(); - return Ok(Async::Ready(())); + return Poll::Ready(()) } } - Ok(Async::NotReady) => { - return Ok(Async::NotReady); + Poll::Pending => { + return Poll::Pending } - Err(()) => unreachable!(), } } } - fn poll_stream_loader_command_rx(&mut self) -> Poll<(), ()> { + fn poll_stream_loader_command_rx(&mut self, cx: &mut Context<'_>) -> Poll<()> { loop { - match self.stream_loader_command_rx.poll() { - Ok(Async::Ready(None)) => { - return Ok(Async::Ready(())); - } - Ok(Async::Ready(Some(StreamLoaderCommand::Fetch(request)))) => { - self.download_range(request.start, request.length); - } - Ok(Async::Ready(Some(StreamLoaderCommand::RandomAccessMode()))) => { - *(self.shared.download_strategy.lock().unwrap()) = - DownloadStrategy::RandomAccess(); - } - Ok(Async::Ready(Some(StreamLoaderCommand::StreamMode()))) => { - *(self.shared.download_strategy.lock().unwrap()) = - DownloadStrategy::Streaming(); - } - Ok(Async::Ready(Some(StreamLoaderCommand::Close()))) => { - return Ok(Async::Ready(())); + match Pin::new(&mut self.stream_loader_command_rx).poll_next(cx) { + Poll::Ready(None) => + return Poll::Ready(()), + Poll::Ready(Some(cmd)) => { + match cmd { + StreamLoaderCommand::Fetch(request) => { + self.download_range(request.start, request.length); + } + StreamLoaderCommand::RandomAccessMode() => { + *(self.shared.download_strategy.lock().unwrap()) = + DownloadStrategy::RandomAccess(); + } + StreamLoaderCommand::StreamMode() => { + + *(self.shared.download_strategy.lock().unwrap()) = + DownloadStrategy::Streaming(); + } + StreamLoaderCommand::Close() => return Poll::Ready(()) + + } } - Ok(Async::NotReady) => return Ok(Async::NotReady), - Err(()) => unreachable!(), + Poll::Pending => return Poll::Pending } } } @@ -909,26 +969,16 @@ impl AudioFileFetch { let _ = complete_tx.send(output); } } - impl Future for AudioFileFetch { - type Item = (); - type Error = (); - - fn poll(&mut self) -> Poll<(), ()> { - match self.poll_stream_loader_command_rx() { - Ok(Async::NotReady) => (), - Ok(Async::Ready(_)) => { - return Ok(Async::Ready(())); - } - Err(()) => unreachable!(), + type Output = (); + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + if let Poll::Ready(()) = self.poll_stream_loader_command_rx(cx) { + return Poll::Ready(()) } - match self.poll_file_data_rx() { - Ok(Async::NotReady) => (), - Ok(Async::Ready(_)) => { - return Ok(Async::Ready(())); - } - Err(()) => unreachable!(), + if let Poll::Ready(()) = self.poll_file_data_rx(cx) { + return Poll::Ready(()) } if let DownloadStrategy::Streaming() = self.get_download_strategy() { @@ -968,8 +1018,7 @@ impl Future for AudioFileFetch { } } } - - return Ok(Async::NotReady); + Poll::Pending } } @@ -1009,9 +1058,9 @@ impl Read for AudioFileStreaming { ranges_to_request.subtract_range_set(&download_status.downloaded); ranges_to_request.subtract_range_set(&download_status.requested); - for range in ranges_to_request.iter() { + for &range in ranges_to_request.iter() { self.stream_loader_command_tx - .unbounded_send(StreamLoaderCommand::Fetch(range.clone())) + .unbounded_send(StreamLoaderCommand::Fetch(range)) .unwrap(); } @@ -1058,7 +1107,7 @@ impl Read for AudioFileStreaming { .read_position .store(self.position as usize, atomic::Ordering::Relaxed); - return Ok(read_len); + Ok(read_len) } } diff --git a/audio/src/lib.rs b/audio/src/lib.rs index 3e13c079a..695558870 100644 --- a/audio/src/lib.rs +++ b/audio/src/lib.rs @@ -1,12 +1,13 @@ #[macro_use] -extern crate futures; -#[macro_use] extern crate log; +#[macro_use] +extern crate pin_project; extern crate aes_ctr; extern crate bit_set; extern crate byteorder; extern crate bytes; +extern crate futures; extern crate num_bigint; extern crate num_traits; extern crate tempfile; @@ -24,7 +25,7 @@ mod libvorbis_decoder; mod range_set; pub use decrypt::AudioDecrypt; -pub use fetch::{AudioFile, AudioFileOpen, StreamLoaderController}; +pub use fetch::{AudioFile, StreamLoaderController}; pub use fetch::{ READ_AHEAD_BEFORE_PLAYBACK_ROUNDTRIPS, READ_AHEAD_BEFORE_PLAYBACK_SECONDS, READ_AHEAD_DURING_PLAYBACK_ROUNDTRIPS, READ_AHEAD_DURING_PLAYBACK_SECONDS, From 90905b81bb681d3bd44832513caf58c2a8737019 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Thu, 21 Jan 2021 22:13:09 +0100 Subject: [PATCH 16/75] Improved RangeSet implementation --- audio/src/range_set.rs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/audio/src/range_set.rs b/audio/src/range_set.rs index 449553885..8712dfd41 100644 --- a/audio/src/range_set.rs +++ b/audio/src/range_set.rs @@ -54,11 +54,7 @@ impl RangeSet { } pub fn len(&self) -> usize { - let mut result = 0; - for range in self.ranges.iter() { - result += range.length; - } - return result; + self.ranges.iter().map(|r| r.length).fold(0, std::ops::Add::add) } pub fn get_range(&self, index: usize) -> Range { @@ -98,12 +94,12 @@ impl RangeSet { return false; } } - return true; + true } pub fn add_range(&mut self, range: &Range) { - if range.length <= 0 { - // the interval is empty or invalid -> nothing to do. + if range.length == 0 { + // the interval is empty -> nothing to do. return; } @@ -111,7 +107,7 @@ impl RangeSet { // the new range is clear of any ranges we already iterated over. if range.end() < self.ranges[index].start { // the new range starts after anything we already passed and ends before the next range starts (they don't touch) -> insert it. - self.ranges.insert(index, range.clone()); + self.ranges.insert(index, *range); return; } else if range.start <= self.ranges[index].end() && self.ranges[index].start <= range.end() @@ -119,7 +115,7 @@ impl RangeSet { // the new range overlaps (or touches) the first range. They are to be merged. // In addition we might have to merge further ranges in as well. - let mut new_range = range.clone(); + let mut new_range = *range; while index < self.ranges.len() && self.ranges[index].start <= new_range.end() { let new_end = max(new_range.end(), self.ranges[index].end()); @@ -134,7 +130,7 @@ impl RangeSet { } // the new range is after everything else -> just add it - self.ranges.push(range.clone()); + self.ranges.push(*range); } #[allow(dead_code)] @@ -152,7 +148,7 @@ impl RangeSet { } pub fn subtract_range(&mut self, range: &Range) { - if range.length <= 0 { + if range.length == 0 { return; } From 0895f17f8a85bdcf1624138fac5c3960796240b7 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Thu, 21 Jan 2021 22:22:32 +0100 Subject: [PATCH 17/75] Migrated playback crate to futures 0.3 --- playback/Cargo.toml | 4 +- playback/src/player.rs | 211 +++++++++++++++++++++-------------------- 2 files changed, 109 insertions(+), 106 deletions(-) diff --git a/playback/Cargo.toml b/playback/Cargo.toml index edd0951fd..104518517 100644 --- a/playback/Cargo.toml +++ b/playback/Cargo.toml @@ -18,9 +18,9 @@ path = "../metadata" version = "0.1.3" [dependencies] -futures = "0.1" +futures = "0.3" log = "0.4" -byteorder = "1.3" +byteorder = "1.4" shell-words = "1.0.0" alsa = { version = "0.2", optional = true } diff --git a/playback/src/player.rs b/playback/src/player.rs index 125184a01..df442f0af 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -1,20 +1,3 @@ -use byteorder::{LittleEndian, ReadBytesExt}; -use futures; -use futures::{future, Async, Future, Poll, Stream}; -use std; -use std::borrow::Cow; -use std::cmp::max; -use std::io::{Read, Result, Seek, SeekFrom}; -use std::mem; -use std::thread; -use std::time::{Duration, Instant}; - -use crate::config::{Bitrate, PlayerConfig}; -use librespot_core::session::Session; -use librespot_core::spotify_id::SpotifyId; - -use librespot_core::util::SeqGenerator; - use crate::audio::{AudioDecrypt, AudioFile, StreamLoaderController}; use crate::audio::{VorbisDecoder, VorbisPacket}; use crate::audio::{ @@ -22,13 +5,33 @@ use crate::audio::{ READ_AHEAD_DURING_PLAYBACK_ROUNDTRIPS, READ_AHEAD_DURING_PLAYBACK_SECONDS, }; use crate::audio_backend::Sink; +use crate::config::{Bitrate, PlayerConfig}; use crate::metadata::{AudioItem, FileFormat}; use crate::mixer::AudioFilter; +use librespot_core::session::Session; +use librespot_core::spotify_id::SpotifyId; +use librespot_core::util::SeqGenerator; + +use byteorder::{LittleEndian, ReadBytesExt}; +use futures::{ + channel::{mpsc, oneshot}, + future, Future, Stream, StreamExt, +}; +use std::io::{Read, Seek, SeekFrom}; +use std::mem; +use std::thread; +use std::time::{Duration, Instant}; +use std::{borrow::Cow, io}; +use std::{ + cmp::max, + pin::Pin, + task::{Context, Poll}, +}; const PRELOAD_NEXT_TRACK_BEFORE_END_DURATION_MS: u32 = 30000; pub struct Player { - commands: Option>, + commands: Option>, thread_handle: Option>, play_request_id_generator: SeqGenerator, } @@ -45,7 +48,7 @@ pub type SinkEventCallback = Box; struct PlayerInternal { session: Session, config: PlayerConfig, - commands: futures::sync::mpsc::UnboundedReceiver, + commands: mpsc::UnboundedReceiver, state: PlayerState, preload: PlayerPreload, @@ -53,7 +56,7 @@ struct PlayerInternal { sink_status: SinkStatus, sink_event_callback: Option, audio_filter: Option>, - event_senders: Vec>, + event_senders: Vec>, } enum PlayerCommand { @@ -70,7 +73,7 @@ enum PlayerCommand { Pause, Stop, Seek(u32), - AddEventSender(futures::sync::mpsc::UnboundedSender), + AddEventSender(mpsc::UnboundedSender), SetSinkEventCallback(Option), EmitVolumeSetEvent(u16), } @@ -182,7 +185,7 @@ impl PlayerEvent { } } -pub type PlayerEventChannel = futures::sync::mpsc::UnboundedReceiver; +pub type PlayerEventChannel = mpsc::UnboundedReceiver; #[derive(Clone, Copy, Debug)] struct NormalisationData { @@ -193,7 +196,7 @@ struct NormalisationData { } impl NormalisationData { - fn parse_from_file(mut file: T) -> Result { + fn parse_from_file(mut file: T) -> io::Result { const SPOTIFY_NORMALIZATION_HEADER_START_OFFSET: u64 = 144; file.seek(SeekFrom::Start(SPOTIFY_NORMALIZATION_HEADER_START_OFFSET)) .unwrap(); @@ -241,8 +244,8 @@ impl Player { where F: FnOnce() -> Box + Send + 'static, { - let (cmd_tx, cmd_rx) = futures::sync::mpsc::unbounded(); - let (event_sender, event_receiver) = futures::sync::mpsc::unbounded(); + let (cmd_tx, cmd_rx) = mpsc::unbounded(); + let (event_sender, event_receiver) = mpsc::unbounded(); let handle = thread::spawn(move || { debug!("new Player[{}]", session.session_id()); @@ -263,7 +266,7 @@ impl Player { // While PlayerInternal is written as a future, it still contains blocking code. // It must be run by using wait() in a dedicated thread. - let _ = internal.wait(); + todo!("How to block in futures 0.3?"); debug!("PlayerInternal thread finished."); }); @@ -314,22 +317,21 @@ impl Player { } pub fn get_player_event_channel(&self) -> PlayerEventChannel { - let (event_sender, event_receiver) = futures::sync::mpsc::unbounded(); + let (event_sender, event_receiver) = mpsc::unbounded(); self.command(PlayerCommand::AddEventSender(event_sender)); event_receiver } - pub fn get_end_of_track_future(&self) -> Box> { - let result = self - .get_player_event_channel() - .filter(|event| match event { - PlayerEvent::EndOfTrack { .. } | PlayerEvent::Stopped { .. } => true, - _ => false, + pub async fn get_end_of_track_future(&self) { + self.get_player_event_channel() + .filter(|event| { + future::ready(matches!( + event, + PlayerEvent::EndOfTrack { .. } | PlayerEvent::Stopped { .. } + )) }) - .into_future() - .map_err(|_| ()) - .map(|_| ()); - Box::new(result) + .for_each(|_| future::ready(())) + .await } pub fn set_sink_event_callback(&self, callback: Option) { @@ -367,7 +369,7 @@ enum PlayerPreload { None, Loading { track_id: SpotifyId, - loader: Box>, + loader: Pin>>>, }, Ready { track_id: SpotifyId, @@ -383,7 +385,7 @@ enum PlayerState { track_id: SpotifyId, play_request_id: u64, start_playback: bool, - loader: Box>, + loader: Pin>>>, }, Paused { track_id: SpotifyId, @@ -573,22 +575,23 @@ struct PlayerTrackLoader { } impl PlayerTrackLoader { - fn find_available_alternative<'a>(&self, audio: &'a AudioItem) -> Option> { + async fn find_available_alternative<'a>( + &self, + audio: &'a AudioItem, + ) -> Option> { if audio.available { Some(Cow::Borrowed(audio)) + } else if let Some(alternatives) = &audio.alternatives { + let alternatives = alternatives + .iter() + .map(|alt_id| AudioItem::get_audio_item(&self.session, *alt_id)); + let alternatives = future::try_join_all(alternatives).await.unwrap(); + alternatives + .into_iter() + .find(|alt| alt.available) + .map(Cow::Owned) } else { - if let Some(alternatives) = &audio.alternatives { - let alternatives = alternatives - .iter() - .map(|alt_id| AudioItem::get_audio_item(&self.session, *alt_id)); - let alternatives = future::join_all(alternatives).wait().unwrap(); - alternatives - .into_iter() - .find(|alt| alt.available) - .map(Cow::Owned) - } else { - None - } + None } } @@ -611,8 +614,12 @@ impl PlayerTrackLoader { } } - fn load_track(&self, spotify_id: SpotifyId, position_ms: u32) -> Option { - let audio = match AudioItem::get_audio_item(&self.session, spotify_id).wait() { + async fn load_track( + &self, + spotify_id: SpotifyId, + position_ms: u32, + ) -> Option { + let audio = match AudioItem::get_audio_item(&self.session, spotify_id).await { Ok(audio) => audio, Err(_) => { error!("Unable to load audio item."); @@ -622,7 +629,7 @@ impl PlayerTrackLoader { info!("Loading <{}> with Spotify URI <{}>", audio.name, audio.uri); - let audio = match self.find_available_alternative(&audio) { + let audio = match self.find_available_alternative(&audio).await { Some(audio) => audio, None => { warn!("<{}> is not available", audio.uri); @@ -675,7 +682,7 @@ impl PlayerTrackLoader { play_from_beginning, ); - let encrypted_file = match encrypted_file.wait() { + let encrypted_file = match encrypted_file.await { Ok(encrypted_file) => encrypted_file, Err(_) => { error!("Unable to load encrypted file."); @@ -693,7 +700,7 @@ impl PlayerTrackLoader { stream_loader_controller.set_random_access_mode(); } - let key = match key.wait() { + let key = match key.await { Ok(key) => key, Err(_) => { error!("Unable to load decryption key"); @@ -738,10 +745,9 @@ impl PlayerTrackLoader { } impl Future for PlayerInternal { - type Item = (); - type Error = (); + type Output = (); - fn poll(&mut self) -> Poll<(), ()> { + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { // While this is written as a future, it still contains blocking code. // It must be run on its own thread. @@ -749,14 +755,13 @@ impl Future for PlayerInternal { let mut all_futures_completed_or_not_ready = true; // process commands that were sent to us - let cmd = match self.commands.poll() { - Ok(Async::Ready(None)) => return Ok(Async::Ready(())), // client has disconnected - shut down. - Ok(Async::Ready(Some(cmd))) => { + let cmd = match Pin::new(&mut self.commands).poll_next(cx) { + Poll::Ready(None) => return Poll::Ready(()), // client has disconnected - shut down. + Poll::Ready(Some(cmd)) => { all_futures_completed_or_not_ready = false; Some(cmd) } - Ok(Async::NotReady) => None, - Err(_) => None, + _ => None, }; if let Some(cmd) = cmd { @@ -771,8 +776,8 @@ impl Future for PlayerInternal { play_request_id, } = self.state { - match loader.poll() { - Ok(Async::Ready(loaded_track)) => { + match loader.as_mut().poll(cx) { + Poll::Ready(Ok(loaded_track)) => { self.start_playback( track_id, play_request_id, @@ -783,8 +788,7 @@ impl Future for PlayerInternal { panic!("The state wasn't changed by start_playback()"); } } - Ok(Async::NotReady) => (), - Err(_) => { + Poll::Ready(Err(_)) => { warn!("Unable to load <{:?}>\nSkipping to next track", track_id); assert!(self.state.is_loading()); self.send_event(PlayerEvent::EndOfTrack { @@ -792,6 +796,7 @@ impl Future for PlayerInternal { play_request_id, }) } + Poll::Pending => (), } } @@ -801,16 +806,15 @@ impl Future for PlayerInternal { track_id, } = self.preload { - match loader.poll() { - Ok(Async::Ready(loaded_track)) => { + match loader.as_mut().poll(cx) { + Poll::Ready(Ok(loaded_track)) => { self.send_event(PlayerEvent::Preloading { track_id }); self.preload = PlayerPreload::Ready { track_id, loaded_track, }; } - Ok(Async::NotReady) => (), - Err(_) => { + Poll::Ready(Err(_)) => { debug!("Unable to preload {:?}", track_id); self.preload = PlayerPreload::None; // Let Spirc know that the track was unavailable. @@ -827,6 +831,7 @@ impl Future for PlayerInternal { }); } } + Poll::Pending => (), } } @@ -847,8 +852,7 @@ impl Future for PlayerInternal { let packet = decoder.next_packet().expect("Vorbis error"); if let Some(ref packet) = packet { - *stream_position_pcm = - *stream_position_pcm + (packet.data().len() / 2) as u64; + *stream_position_pcm += (packet.data().len() / 2) as u64; let stream_position_millis = Self::position_pcm_to_ms(*stream_position_pcm); let notify_about_position = match *reported_nominal_start_time { @@ -858,11 +862,7 @@ impl Future for PlayerInternal { let lag = (Instant::now() - reported_nominal_start_time).as_millis() as i64 - stream_position_millis as i64; - if lag > 1000 { - true - } else { - false - } + lag > 1000 } }; if notify_about_position { @@ -918,11 +918,11 @@ impl Future for PlayerInternal { } if self.session.is_invalid() { - return Ok(Async::Ready(())); + return Poll::Ready(()); } if (!self.state.is_playing()) && all_futures_completed_or_not_ready { - return Ok(Async::NotReady); + return Poll::Pending; } } } @@ -1066,7 +1066,9 @@ impl PlayerInternal { editor.modify_stream(&mut packet.data_mut()) }; - if self.config.normalisation && normalisation_factor != 1.0 { + if self.config.normalisation + && (normalisation_factor - 1.0).abs() < f32::EPSILON + { for x in packet.data_mut().iter_mut() { *x = (*x as f32 * normalisation_factor) as i16; } @@ -1363,9 +1365,7 @@ impl PlayerInternal { self.preload = PlayerPreload::None; // If we don't have a loader yet, create one from scratch. - let loader = loader - .or_else(|| Some(self.load_track(track_id, position_ms))) - .unwrap(); + let loader = loader.unwrap_or_else(|| Box::pin(self.load_track(track_id, position_ms))); // Set ourselves to a loading state. self.state = PlayerState::Loading { @@ -1420,7 +1420,10 @@ impl PlayerInternal { // schedule the preload of the current track if desired. if preload_track { let loader = self.load_track(track_id, 0); - self.preload = PlayerPreload::Loading { track_id, loader } + self.preload = PlayerPreload::Loading { + track_id, + loader: Box::pin(loader), + } } } @@ -1532,34 +1535,34 @@ impl PlayerInternal { } } - fn load_track( + pub fn load_track( &self, spotify_id: SpotifyId, position_ms: u32, - ) -> Box> { + ) -> impl Future> + 'static { // This method creates a future that returns the loaded stream and associated info. // Ideally all work should be done using asynchronous code. However, seek() on the // audio stream is implemented in a blocking fashion. Thus, we can't turn it into future // easily. Instead we spawn a thread to do the work and return a one-shot channel as the // future to work with. - let loader = PlayerTrackLoader { - session: self.session.clone(), - config: self.config.clone(), - }; + let session = self.session.clone(); + let config = self.config.clone(); - let (result_tx, result_rx) = futures::sync::oneshot::channel(); + async move { + let loader = PlayerTrackLoader { session, config }; - std::thread::spawn(move || { - loader - .load_track(spotify_id, position_ms) - .and_then(move |data| { + let (result_tx, result_rx) = oneshot::channel(); + + std::thread::spawn(move || { + todo!("How to block in futures 0.3?") + /*if let Some(data) = block_on(loader.load_track(spotify_id, position_ms)) { let _ = result_tx.send(data); - Some(()) - }); - }); + }*/ + }); - Box::new(result_rx.map_err(|_| ())) + result_rx.await.map_err(|_| ()) + } } fn preload_data_before_playback(&mut self) { @@ -1689,13 +1692,13 @@ impl Subfile { } impl Read for Subfile { - fn read(&mut self, buf: &mut [u8]) -> Result { + fn read(&mut self, buf: &mut [u8]) -> io::Result { self.stream.read(buf) } } impl Seek for Subfile { - fn seek(&mut self, mut pos: SeekFrom) -> Result { + fn seek(&mut self, mut pos: SeekFrom) -> io::Result { pos = match pos { SeekFrom::Start(offset) => SeekFrom::Start(offset + self.offset), x => x, From 6c9d8c8d83dd23cc69f1a00941a4feeadcb370d7 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Fri, 22 Jan 2021 22:32:45 +0100 Subject: [PATCH 18/75] Replace pin_project and updated dependencies --- audio/Cargo.toml | 4 +-- audio/src/fetch.rs | 74 ++++++++++++++++++----------------------- audio/src/lib.rs | 4 ++- core/Cargo.toml | 9 +++-- core/src/lib.rs | 4 +-- core/src/mercury/mod.rs | 12 ++++--- 6 files changed, 54 insertions(+), 53 deletions(-) diff --git a/audio/Cargo.toml b/audio/Cargo.toml index f9d232b37..5e950cdc3 100644 --- a/audio/Cargo.toml +++ b/audio/Cargo.toml @@ -16,11 +16,11 @@ bit-set = "0.5" byteorder = "1.4" bytes = "1.0" futures = "0.3" -lewton = "0.9" +lewton = "0.10" log = "0.4" num-bigint = "0.3" num-traits = "0.2" -pin-project = "1.0" +pin-project-lite = "0.2.4" tempfile = "3.1" librespot-tremor = { version = "0.1.0", optional = true } diff --git a/audio/src/fetch.rs b/audio/src/fetch.rs index 5d15866c6..51dddc6bc 100644 --- a/audio/src/fetch.rs +++ b/audio/src/fetch.rs @@ -502,8 +502,8 @@ async fn audio_file_fetch_receive_data( future::ready(if request_length == 0 { Err(TryFoldErr::FinishEarly) - } else { - Ok(()) + } else { + Ok(()) }) }) .await; @@ -532,7 +532,7 @@ async fn audio_file_fetch_receive_data( ); } } -/* +/* async fn audio_file_fetch( session: Session, shared: Arc, @@ -689,20 +689,21 @@ async fn audio_file_fetch( future::select_all(vec![f1, f2, f3]).await }*/ -#[pin_project] -struct AudioFileFetch { - session: Session, - shared: Arc, - output: Option, +pin_project! { + struct AudioFileFetch { + session: Session, + shared: Arc, + output: Option, - file_data_tx: mpsc::UnboundedSender, - #[pin] - file_data_rx: mpsc::UnboundedReceiver, + file_data_tx: mpsc::UnboundedSender, + #[pin] + file_data_rx: mpsc::UnboundedReceiver, - #[pin] - stream_loader_command_rx: mpsc::UnboundedReceiver, - complete_tx: Option>, - network_response_times_ms: Vec, + #[pin] + stream_loader_command_rx: mpsc::UnboundedReceiver, + complete_tx: Option>, + network_response_times_ms: Vec, + } } impl AudioFileFetch { @@ -853,8 +854,6 @@ impl AudioFileFetch { } } - - fn poll_file_data_rx(&mut self, cx: &mut Context<'_>) -> Poll<()> { loop { match Pin::new(&mut self.file_data_rx).poll_next(cx) { @@ -923,12 +922,10 @@ impl AudioFileFetch { if full { self.finish(); - return Poll::Ready(()) + return Poll::Ready(()); } } - Poll::Pending => { - return Poll::Pending - } + Poll::Pending => return Poll::Pending, } } } @@ -936,27 +933,22 @@ impl AudioFileFetch { fn poll_stream_loader_command_rx(&mut self, cx: &mut Context<'_>) -> Poll<()> { loop { match Pin::new(&mut self.stream_loader_command_rx).poll_next(cx) { - Poll::Ready(None) => - return Poll::Ready(()), - Poll::Ready(Some(cmd)) => { - match cmd { - StreamLoaderCommand::Fetch(request) => { - self.download_range(request.start, request.length); - } - StreamLoaderCommand::RandomAccessMode() => { - *(self.shared.download_strategy.lock().unwrap()) = + Poll::Ready(None) => return Poll::Ready(()), + Poll::Ready(Some(cmd)) => match cmd { + StreamLoaderCommand::Fetch(request) => { + self.download_range(request.start, request.length); + } + StreamLoaderCommand::RandomAccessMode() => { + *(self.shared.download_strategy.lock().unwrap()) = DownloadStrategy::RandomAccess(); - } - StreamLoaderCommand::StreamMode() => { - - *(self.shared.download_strategy.lock().unwrap()) = + } + StreamLoaderCommand::StreamMode() => { + *(self.shared.download_strategy.lock().unwrap()) = DownloadStrategy::Streaming(); - } - StreamLoaderCommand::Close() => return Poll::Ready(()) - } - } - Poll::Pending => return Poll::Pending + StreamLoaderCommand::Close() => return Poll::Ready(()), + }, + Poll::Pending => return Poll::Pending, } } } @@ -974,11 +966,11 @@ impl Future for AudioFileFetch { fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { if let Poll::Ready(()) = self.poll_stream_loader_command_rx(cx) { - return Poll::Ready(()) + return Poll::Ready(()); } if let Poll::Ready(()) = self.poll_file_data_rx(cx) { - return Poll::Ready(()) + return Poll::Ready(()); } if let DownloadStrategy::Streaming() = self.get_download_strategy() { diff --git a/audio/src/lib.rs b/audio/src/lib.rs index 695558870..1be1ba88b 100644 --- a/audio/src/lib.rs +++ b/audio/src/lib.rs @@ -1,7 +1,9 @@ +#![allow(clippy::unused_io_amount)] + #[macro_use] extern crate log; #[macro_use] -extern crate pin_project; +extern crate pin_project_lite; extern crate aes_ctr; extern crate bit_set; diff --git a/core/Cargo.toml b/core/Cargo.toml index a9fcc246b..c092c04d8 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -20,14 +20,14 @@ bytes = "1.0" futures = { version = "0.3", features = ["bilock", "unstable"] } hmac = "0.7" httparse = "1.3" -hyper = { version = "0.14", features = ["client", "tcp", "http1", "http2", "stream"] } +hyper = { version = "0.14", features = ["client", "tcp", "http1", "http2"] } log = "0.4" num-bigint = "0.3" num-integer = "0.1" num-traits = "0.2" once_cell = "1.5.2" pbkdf2 = "0.3" -pin-project = "1.0" +pin-project-lite = "0.2.4" protobuf = "~2.14.0" rand = "0.7" serde = "1.0" @@ -35,7 +35,7 @@ serde_derive = "1.0" serde_json = "1.0" sha-1 = "~0.8" shannon = "0.2.0" -tokio = { version = "1.0", features = ["io-util", "rt-multi-thread", "macros" ] } +tokio = { version = "1.0", features = ["io-util", "rt-multi-thread"] } tokio-util = { version = "0.6", features = ["codec"] } url = "1.7" uuid = { version = "0.8", features = ["v4"] } @@ -43,3 +43,6 @@ uuid = { version = "0.8", features = ["v4"] } [build-dependencies] rand = "0.7" vergen = "3.0.4" + +[dev-dependencies] +tokio = {version = "1.0", features = ["macros"] } \ No newline at end of file diff --git a/core/src/lib.rs b/core/src/lib.rs index 65f6f81bd..a15aa7a2d 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -5,7 +5,7 @@ extern crate log; #[macro_use] extern crate serde_derive; #[macro_use] -extern crate pin_project; +extern crate pin_project_lite; extern crate aes; extern crate base64; extern crate byteorder; @@ -25,7 +25,7 @@ extern crate serde; extern crate serde_json; extern crate sha1; extern crate shannon; -extern crate tokio; +pub extern crate tokio; extern crate tokio_util; extern crate url; extern crate uuid; diff --git a/core/src/mercury/mod.rs b/core/src/mercury/mod.rs index e77b4a45b..72360c972 100644 --- a/core/src/mercury/mod.rs +++ b/core/src/mercury/mod.rs @@ -31,14 +31,18 @@ pub struct MercuryPending { callback: Option>>, } -#[pin_project] -pub struct MercuryFuture(#[pin] oneshot::Receiver>); +pin_project! { + pub struct MercuryFuture { + #[pin] + receiver: oneshot::Receiver> + } +} impl Future for MercuryFuture { type Output = Result; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - match self.project().0.poll(cx) { + match self.project().receiver.poll(cx) { Poll::Ready(Ok(x)) => Poll::Ready(x), Poll::Ready(Err(_)) => Poll::Ready(Err(MercuryError)), Poll::Pending => Poll::Pending, @@ -73,7 +77,7 @@ impl MercuryManager { let data = req.encode(&seq); self.session().send_packet(cmd, data); - MercuryFuture(rx) + MercuryFuture { receiver: rx } } pub fn get>(&self, uri: T) -> MercuryFuture { From fe371868046222690f6104ba2742ce73589c2e25 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Fri, 22 Jan 2021 22:51:41 +0100 Subject: [PATCH 19/75] Make librespot_playback work --- playback/src/audio_backend/mod.rs | 8 +- playback/src/audio_backend/pipe.rs | 2 +- playback/src/player.rs | 122 ++++++++++++++--------------- src/lib.rs | 2 +- 4 files changed, 66 insertions(+), 68 deletions(-) diff --git a/playback/src/audio_backend/mod.rs b/playback/src/audio_backend/mod.rs index a9840d42f..21ee3c053 100644 --- a/playback/src/audio_backend/mod.rs +++ b/playback/src/audio_backend/mod.rs @@ -10,7 +10,9 @@ pub trait Sink { fn write(&mut self, data: &[i16]) -> io::Result<()>; } -fn mk_sink(device: Option) -> Box { +pub type SinkBuilder = fn(Option) -> Box; + +fn mk_sink(device: Option) -> Box { Box::new(S::open(device)) } @@ -54,7 +56,7 @@ use self::pipe::StdoutSink; mod subprocess; use self::subprocess::SubprocessSink; -pub const BACKENDS: &'static [(&'static str, fn(Option) -> Box)] = &[ +pub const BACKENDS: &'static [(&'static str, SinkBuilder)] = &[ #[cfg(feature = "alsa-backend")] ("alsa", mk_sink::), #[cfg(feature = "portaudio-backend")] @@ -73,7 +75,7 @@ pub const BACKENDS: &'static [(&'static str, fn(Option) -> Box ("subprocess", mk_sink::), ]; -pub fn find(name: Option) -> Option) -> Box> { +pub fn find(name: Option) -> Option { if let Some(name) = name { BACKENDS .iter() diff --git a/playback/src/audio_backend/pipe.rs b/playback/src/audio_backend/pipe.rs index 2adafe11c..02b8faf56 100644 --- a/playback/src/audio_backend/pipe.rs +++ b/playback/src/audio_backend/pipe.rs @@ -4,7 +4,7 @@ use std::io::{self, Write}; use std::mem; use std::slice; -pub struct StdoutSink(Box); +pub struct StdoutSink(Box); impl Open for StdoutSink { fn open(path: Option) -> StdoutSink { diff --git a/playback/src/player.rs b/playback/src/player.rs index df442f0af..ff0fba24f 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -6,6 +6,7 @@ use crate::audio::{ }; use crate::audio_backend::Sink; use crate::config::{Bitrate, PlayerConfig}; +use crate::librespot_core::tokio; use crate::metadata::{AudioItem, FileFormat}; use crate::mixer::AudioFilter; use librespot_core::session::Session; @@ -19,7 +20,6 @@ use futures::{ }; use std::io::{Read, Seek, SeekFrom}; use std::mem; -use std::thread; use std::time::{Duration, Instant}; use std::{borrow::Cow, io}; use std::{ @@ -32,7 +32,7 @@ const PRELOAD_NEXT_TRACK_BEFORE_END_DURATION_MS: u32 = 30000; pub struct Player { commands: Option>, - thread_handle: Option>, + task_handle: Option>, play_request_id_generator: SeqGenerator, } @@ -52,7 +52,7 @@ struct PlayerInternal { state: PlayerState, preload: PlayerPreload, - sink: Box, + sink: Box, sink_status: SinkStatus, sink_event_callback: Option, audio_filter: Option>, @@ -242,38 +242,38 @@ impl Player { sink_builder: F, ) -> (Player, PlayerEventChannel) where - F: FnOnce() -> Box + Send + 'static, + F: FnOnce() -> Box + Send + 'static, { let (cmd_tx, cmd_rx) = mpsc::unbounded(); let (event_sender, event_receiver) = mpsc::unbounded(); - let handle = thread::spawn(move || { - debug!("new Player[{}]", session.session_id()); - - let internal = PlayerInternal { - session: session, - config: config, - commands: cmd_rx, - - state: PlayerState::Stopped, - preload: PlayerPreload::None, - sink: sink_builder(), - sink_status: SinkStatus::Closed, - sink_event_callback: None, - audio_filter: audio_filter, - event_senders: [event_sender].to_vec(), - }; + debug!("new Player[{}]", session.session_id()); + + let internal = PlayerInternal { + session: session, + config: config, + commands: cmd_rx, + + state: PlayerState::Stopped, + preload: PlayerPreload::None, + sink: sink_builder(), + sink_status: SinkStatus::Closed, + sink_event_callback: None, + audio_filter: audio_filter, + event_senders: [event_sender].to_vec(), + }; - // While PlayerInternal is written as a future, it still contains blocking code. - // It must be run by using wait() in a dedicated thread. - todo!("How to block in futures 0.3?"); + // While PlayerInternal is written as a future, it still contains blocking code. + // It must be run by using wait() in a dedicated thread. + let handle = tokio::spawn(async move { + internal.await; debug!("PlayerInternal thread finished."); }); ( Player { commands: Some(cmd_tx), - thread_handle: Some(handle), + task_handle: Some(handle), play_request_id_generator: SeqGenerator::new(0), }, event_receiver, @@ -347,11 +347,13 @@ impl Drop for Player { fn drop(&mut self) { debug!("Shutting down player thread ..."); self.commands = None; - if let Some(handle) = self.thread_handle.take() { - match handle.join() { - Ok(_) => (), - Err(_) => error!("Player thread panicked!"), - } + if let Some(handle) = self.task_handle.take() { + tokio::spawn(async { + match handle.await { + Ok(_) => (), + Err(_) => error!("Player thread panicked!"), + } + }); } } } @@ -369,11 +371,11 @@ enum PlayerPreload { None, Loading { track_id: SpotifyId, - loader: Pin>>>, + loader: Pin> + Send>>, }, Ready { track_id: SpotifyId, - loaded_track: PlayerLoadedTrackData, + loaded_track: Box, }, } @@ -385,7 +387,7 @@ enum PlayerState { track_id: SpotifyId, play_request_id: u64, start_playback: bool, - loader: Pin>>>, + loader: Pin> + Send>>, }, Paused { track_id: SpotifyId, @@ -430,23 +432,15 @@ impl PlayerState { #[allow(dead_code)] fn is_stopped(&self) -> bool { - use self::PlayerState::*; - match *self { - Stopped => true, - _ => false, - } + matches!(self, Self::Stopped) } fn is_loading(&self) -> bool { - use self::PlayerState::*; - match *self { - Loading { .. } => true, - _ => false, - } + matches!(self, Self::Loading { .. }) } fn decoder(&mut self) -> Option<&mut Decoder> { - use self::PlayerState::*; + use PlayerState::*; match *self { Stopped | EndOfTrack { .. } | Loading { .. } => None, Paused { @@ -575,10 +569,10 @@ struct PlayerTrackLoader { } impl PlayerTrackLoader { - async fn find_available_alternative<'a>( - &self, - audio: &'a AudioItem, - ) -> Option> { + async fn find_available_alternative<'a, 'b>( + &'a self, + audio: &'b AudioItem, + ) -> Option> { if audio.available { Some(Cow::Borrowed(audio)) } else if let Some(alternatives) = &audio.alternatives { @@ -716,7 +710,7 @@ impl PlayerTrackLoader { } Err(_) => { warn!("Unable to extract normalisation data, using default value."); - 1.0 as f32 + 1.0_f32 } }; @@ -811,7 +805,7 @@ impl Future for PlayerInternal { self.send_event(PlayerEvent::Preloading { track_id }); self.preload = PlayerPreload::Ready { track_id, - loaded_track, + loaded_track: Box::new(loaded_track), }; } Poll::Ready(Err(_)) => { @@ -1061,7 +1055,7 @@ impl PlayerInternal { fn handle_packet(&mut self, packet: Option, normalisation_factor: f32) { match packet { Some(mut packet) => { - if packet.data().len() > 0 { + if !packet.data().is_empty() { if let Some(ref editor) = self.audio_filter { editor.modify_stream(&mut packet.data_mut()) }; @@ -1216,10 +1210,9 @@ impl PlayerInternal { loaded_track .stream_loader_controller .set_random_access_mode(); - let _ = loaded_track.decoder.seek(position_ms as i64); // This may be blocking. - // But most likely the track is fully - // loaded already because we played - // to the end of it. + let _ = tokio::task::block_in_place(|| { + loaded_track.decoder.seek(position_ms as i64) + }); loaded_track.stream_loader_controller.set_stream_mode(); loaded_track.stream_position_pcm = Self::position_ms_to_pcm(position_ms); } @@ -1252,7 +1245,7 @@ impl PlayerInternal { // we can use the current decoder. Ensure it's at the correct position. if Self::position_ms_to_pcm(position_ms) != *stream_position_pcm { stream_loader_controller.set_random_access_mode(); - let _ = decoder.seek(position_ms as i64); // This may be blocking. + let _ = tokio::task::block_in_place(|| decoder.seek(position_ms as i64)); stream_loader_controller.set_stream_mode(); *stream_position_pcm = Self::position_ms_to_pcm(position_ms); } @@ -1320,10 +1313,12 @@ impl PlayerInternal { loaded_track .stream_loader_controller .set_random_access_mode(); - let _ = loaded_track.decoder.seek(position_ms as i64); // This may be blocking + let _ = tokio::task::block_in_place(|| { + loaded_track.decoder.seek(position_ms as i64) + }); loaded_track.stream_loader_controller.set_stream_mode(); } - self.start_playback(track_id, play_request_id, loaded_track, play); + self.start_playback(track_id, play_request_id, *loaded_track, play); return; } else { unreachable!(); @@ -1539,7 +1534,7 @@ impl PlayerInternal { &self, spotify_id: SpotifyId, position_ms: u32, - ) -> impl Future> + 'static { + ) -> impl Future> + Send + 'static { // This method creates a future that returns the loaded stream and associated info. // Ideally all work should be done using asynchronous code. However, seek() on the // audio stream is implemented in a blocking fashion. Thus, we can't turn it into future @@ -1554,11 +1549,10 @@ impl PlayerInternal { let (result_tx, result_rx) = oneshot::channel(); - std::thread::spawn(move || { - todo!("How to block in futures 0.3?") - /*if let Some(data) = block_on(loader.load_track(spotify_id, position_ms)) { + tokio::spawn(async move { + if let Some(data) = loader.load_track(spotify_id, position_ms).await { let _ = result_tx.send(data); - }*/ + } }); result_rx.await.map_err(|_| ()) @@ -1588,7 +1582,9 @@ impl PlayerInternal { * bytes_per_second as f64) as usize, (READ_AHEAD_BEFORE_PLAYBACK_SECONDS * bytes_per_second as f64) as usize, ); - stream_loader_controller.fetch_next_blocking(wait_for_data_length); + tokio::task::block_in_place(|| { + stream_loader_controller.fetch_next_blocking(wait_for_data_length) + }); } } } diff --git a/src/lib.rs b/src/lib.rs index 610062e28..31bac3437 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,7 @@ #![cfg_attr(feature = "cargo-clippy", allow(unused_io_amount))] pub extern crate librespot_audio as audio; -pub extern crate librespot_connect as connect; +// pub extern crate librespot_connect as connect; pub extern crate librespot_core as core; pub extern crate librespot_metadata as metadata; pub extern crate librespot_playback as playback; From 91d7d0422b05b03f437e4789f284ceac0592131f Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Sat, 23 Jan 2021 00:02:49 +0100 Subject: [PATCH 20/75] Preparing main crate for testing --- Cargo.lock | 3154 ++++++++++++++++++++++----------------------------- Cargo.toml | 40 +- src/lib.rs | 1 - src/main.rs | 620 ---------- 4 files changed, 1379 insertions(+), 2436 deletions(-) delete mode 100644 src/main.rs diff --git a/Cargo.lock b/Cargo.lock index c4fc5c43f..5813a707c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,3506 +2,3084 @@ # It is not intended for manual editing. [[package]] name = "addr2line" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7" dependencies = [ - "gimli 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gimli", ] [[package]] name = "adler" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" [[package]] name = "adler32" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" [[package]] name = "aes" -version = "0.3.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" dependencies = [ - "aes-soft 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "aes-soft", + "aesni", + "cipher", ] [[package]] name = "aes-ctr" -version = "0.3.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7729c3cde54d67063be556aeac75a81330d802f0259500ca40cb52967f975763" dependencies = [ - "aes-soft 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ctr 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "stream-cipher 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "aes-soft", + "aesni", + "cipher", + "ctr", ] [[package]] name = "aes-soft" -version = "0.3.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" dependencies = [ - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cipher", + "opaque-debug 0.3.0", ] [[package]] name = "aesni" -version = "0.6.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" dependencies = [ - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "stream-cipher 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cipher", + "opaque-debug 0.3.0", ] [[package]] name = "alsa" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4a0d4ebc8b23041c5de9bc9aee13b4bad844a589479701f31a5934cfe4aeb32" dependencies = [ - "alsa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "nix 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "alsa-sys 0.1.2", + "bitflags 0.9.1", + "libc", + "nix 0.9.0", ] [[package]] name = "alsa" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb213f6b3e4b1480a60931ca2035794aa67b73103d254715b1db7b70dcb3c934" dependencies = [ - "alsa-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "alsa-sys 0.3.1", + "bitflags 1.2.1", + "libc", + "nix 0.15.0", ] [[package]] name = "alsa-sys" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0edcbbf9ef68f15ae1b620f722180b82a98b6f0628d30baa6b8d2a5abc87d58" dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "pkg-config", ] [[package]] name = "alsa-sys" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527" dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "pkg-config", ] [[package]] name = "anyhow" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "arc-swap" -version = "0.4.7" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1" [[package]] name = "ascii" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" [[package]] -name = "atty" -version = "0.2.14" +name = "async-stream" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3670df70cbc01729f901f94c887814b3c68db038aad1329a418bae178bc5295c" dependencies = [ - "hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "async-stream-impl", + "futures-core", ] [[package]] -name = "autocfg" -version = "1.0.0" +name = "async-stream-impl" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3548b8efc9f8e8a5a0a2808c5bd8451a9031b9e5b879a79590304ae928b0a70" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] -name = "backtrace" -version = "0.3.55" +name = "async-trait" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d3a45e77e34375a7923b1e8febb049bb011f064714a8e17a1a616fef01da13d" dependencies = [ - "addr2line 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "object 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "base64" -version = "0.9.3" +name = "autocfg" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] -name = "base64" -version = "0.10.1" +name = "backtrace" +version = "0.3.56" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d117600f438b1707d4e4ae15d3595657288f8235a0eb593e80ecc98ab34e1bc" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "addr2line", + "cfg-if 1.0.0", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", ] +[[package]] +name = "base-x" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" + [[package]] name = "base64" -version = "0.11.0" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" +dependencies = [ + "byteorder", + "safemem", +] [[package]] name = "base64" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] name = "bindgen" -version = "0.53.3" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2da379dbebc0b76ef63ca68d8fc6e71c0f13e59432e0987e508c1820e6ab5239" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cexpr 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "clang-sys 0.29.3 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hash 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", ] [[package]] name = "bit-set" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de" dependencies = [ - "bit-vec 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bit-vec", ] [[package]] name = "bit-vec" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "block-buffer" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" dependencies = [ - "block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "block-cipher-trait" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "block-modes" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "block-padding", + "byte-tools", + "byteorder", + "generic-array 0.12.3", ] [[package]] name = "block-padding" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" dependencies = [ - "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools", ] [[package]] name = "bumpalo" version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" [[package]] name = "byte-tools" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "byteorder" -version = "1.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bytes" -version = "0.4.12" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" [[package]] name = "bytes" -version = "0.5.6" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" [[package]] name = "cc" -version = "1.0.65" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" [[package]] name = "cesu8" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" [[package]] name = "cexpr" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" dependencies = [ - "nom 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "nom", ] [[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.13" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" dependencies = [ - "num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "num-integer", + "num-traits", + "time 0.1.43", + "winapi", ] [[package]] name = "chunked_transfer" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7477065d45a8fe57167bf3cf8bcd3729b54cfcb81cca49bda2d038ea89ae82ca" [[package]] -name = "clang-sys" -version = "0.29.3" +name = "cipher" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" dependencies = [ - "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.14.4", ] [[package]] -name = "cloudabi" -version = "0.0.3" +name = "clang-sys" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0659001ab56b791be01d4b729c44376edc6718cf389a502e579b77b758f3296c" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "glob", + "libc", + "libloading", ] [[package]] name = "cloudabi" -version = "0.1.0" +version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", ] [[package]] name = "combine" version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" dependencies = [ - "ascii 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ascii", + "byteorder", + "either", + "memchr", + "unreachable", ] [[package]] name = "combine" -version = "4.4.0" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4369b5e4c0cddf64ad8981c0111e7df4f7078f4d6ba98fb31f2e17c4c57b7e" dependencies = [ - "bytes 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-project-lite 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "memchr", ] +[[package]] +name = "const_fn" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6" + [[package]] name = "cookie" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784ad0fbab4f3e9cef09f20e0aea6000ae08d2cb98ac4c0abc53df18803d702f" +dependencies = [ + "percent-encoding 2.1.0", + "time 0.2.24", + "version_check", +] + +[[package]] +name = "cookie_store" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3818dfca4b0cb5211a659bbcbb94225b7127407b2b135e650d717bfb78ab10d3" dependencies = [ - "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cookie", + "idna 0.2.0", + "log", + "publicsuffix", + "serde", + "serde_json", + "time 0.2.24", + "url 2.2.0", ] [[package]] name = "core-foundation-sys" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" [[package]] name = "coreaudio-rs" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f229761965dad3e9b11081668a6ea00f1def7aa46062321b5ec245b834f6e491" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "coreaudio-sys 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "coreaudio-sys", ] [[package]] name = "coreaudio-sys" -version = "0.2.5" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b7e3347be6a09b46aba228d6608386739fb70beff4f61e07422da87b0bb31fa" dependencies = [ - "bindgen 0.53.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bindgen", ] [[package]] name = "cpal" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05631e2089dfa5d3b6ea1cfbbfd092e2ee5deeb69698911bc976b28b746d3657" dependencies = [ - "alsa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "coreaudio-rs 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "jni 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "mach 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ndk 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ndk-glue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "oboe 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", - "stdweb 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", - "web-sys 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "alsa 0.4.3", + "core-foundation-sys", + "coreaudio-rs", + "jni 0.17.0", + "js-sys", + "lazy_static", + "libc", + "mach", + "ndk", + "ndk-glue", + "nix 0.15.0", + "oboe", + "parking_lot", + "stdweb 0.1.3", + "thiserror", + "web-sys", + "winapi", ] [[package]] name = "crc32fast" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" dependencies = [ - "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-deque" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-queue" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-queue" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-utils" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-utils" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", ] [[package]] name = "crypto-mac" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" dependencies = [ - "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.3", + "subtle", ] [[package]] name = "ctr" -version = "0.3.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f" dependencies = [ - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "stream-cipher 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cipher", ] [[package]] name = "darling" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" dependencies = [ - "darling_core 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", - "darling_macro 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "darling_core", + "darling_macro", ] [[package]] name = "darling_core" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" dependencies = [ - "fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "ident_case 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", ] [[package]] name = "darling_macro" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" dependencies = [ - "darling_core 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "darling_core", + "quote", + "syn", ] [[package]] name = "derivative" -version = "2.1.1" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaed5874effa6cde088c644ddcdcb4ffd1511391c5be4fdd7a5ccd02c7e4a183" dependencies = [ - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "digest" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" dependencies = [ - "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.3", ] [[package]] -name = "dns-sd" -version = "0.1.3" +name = "discard" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" [[package]] name = "either" version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "env_logger" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "error-chain" -version = "0.12.2" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" dependencies = [ - "backtrace 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace", + "version_check", ] [[package]] name = "fake-simd" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" [[package]] name = "fetch_unroll" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d44807d562d137f063cbfe209da1c3f9f2fa8375e11166ef495daab7b847f9" dependencies = [ - "libflate 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "tar 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "ureq 0.11.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libflate", + "tar", + "ureq", ] [[package]] name = "filetime" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8" dependencies = [ - "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "libc", + "redox_syscall 0.2.4", + "winapi", ] [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00" dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "matches", + "percent-encoding 2.1.0", ] [[package]] name = "fuchsia-cprng" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" [[package]] -name = "fuchsia-zircon" -version = "0.3.3" +name = "futures" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9052a1a50244d8d5aa9bf55cbc2fb6f357c86cc52e46c62ed390a7180cf150" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", ] -[[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "futures" -version = "0.1.29" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "futures-channel" -version = "0.3.5" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2d31b7ec7efab6eefc7c57233bb10b847986139d88cc2f5a02a1ae6871a1846" dependencies = [ - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core", + "futures-sink", ] [[package]] name = "futures-core" -version = "0.3.5" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79e5145dde8da7d1b3892dad07a9c98fc04bc39892b1ecc9692cf53e2b780a65" [[package]] -name = "futures-cpupool" -version = "0.1.8" +name = "futures-executor" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9e59fdc009a4b3096bf94f740a0f2424c082521f20a9b08c5c07c48d90fd9b9" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core", + "futures-task", + "futures-util", ] [[package]] -name = "futures-executor" -version = "0.3.5" +name = "futures-io" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "28be053525281ad8259d47e4de5de657b25e7bac113458555bb4b70bc6870500" [[package]] name = "futures-macro" -version = "0.3.5" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c287d25add322d9f9abdcdc5927ca398917996600182178774032e9f8258fedd" dependencies = [ - "proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "futures-sink" -version = "0.3.5" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf5c69029bda2e743fddd0582d1083951d65cc9539aebf8812f36c3491342d6" [[package]] name = "futures-task" -version = "0.3.5" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13de07eb8ea81ae445aca7b69f5f7bf15d7bf4912d8ca37d6645c77ae8a58d86" dependencies = [ - "once_cell 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "once_cell", ] [[package]] name = "futures-util" -version = "0.3.5" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "632a8cd0f2a4b3fdea1657f08bde063848c3bd00f9bbf6e256b8be78802e624b" dependencies = [ - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-macro 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-project 0.4.22 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-nested 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "proc-macro-hack", + "proc-macro-nested", + "slab", ] [[package]] name = "gcc" version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" [[package]] name = "generic-array" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" dependencies = [ - "typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "typenum", ] [[package]] -name = "getopts" -version = "0.2.21" +name = "generic-array" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" dependencies = [ - "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "typenum", + "version_check", ] [[package]] name = "getrandom" -version = "0.1.14" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.10.1+wasi-snapshot-preview1", ] [[package]] name = "gimli" version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" [[package]] name = "glib" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c685013b7515e668f1b57a165b009d4d28cb139a8a989bbd699c10dad29d0c5" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-executor 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "glib-macros 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "glib-sys 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gobject-sys 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "once_cell 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "futures-util", + "glib-macros", + "glib-sys", + "gobject-sys", + "libc", + "once_cell", ] [[package]] name = "glib-macros" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41486a26d1366a8032b160b59065a59fb528530a46a49f627e7048fb8c064039" dependencies = [ - "anyhow 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-crate 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-error 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "anyhow", + "heck", + "itertools", + "proc-macro-crate", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "glib-sys" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e9b997a66e9a23d073f2b1abb4dbfc3925e0b8952f67efd8d9b6e168e4cdc1" dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "system-deps 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "system-deps", ] [[package]] name = "glob" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "gobject-sys" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "952133b60c318a62bf82ee75b93acc7e84028a093e06b9e27981c2b6fe68218c" dependencies = [ - "glib-sys 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "system-deps 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys", + "libc", + "system-deps", ] [[package]] name = "gstreamer" version = "0.16.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d50f822055923f1cbede233aa5dfd4ee957cf328fb3076e330886094e11d6cf" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "glib 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)", - "glib-sys 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gobject-sys 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "muldiv 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-rational 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "once_cell 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "paste 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "pretty-hex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "cfg-if 1.0.0", + "futures-channel", + "futures-core", + "futures-util", + "glib", + "glib-sys", + "gobject-sys", + "gstreamer-sys", + "libc", + "muldiv", + "num-rational", + "once_cell", + "paste", + "pretty-hex", + "thiserror", ] [[package]] name = "gstreamer-app" version = "0.16.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc80888271338c3ede875d8cafc452eb207476ff5539dcbe0018a8f5b827af0e" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "glib 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)", - "glib-sys 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gobject-sys 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer 0.16.5 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-app-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-base 0.16.5 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "once_cell 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "futures-core", + "futures-sink", + "glib", + "glib-sys", + "gobject-sys", + "gstreamer", + "gstreamer-app-sys", + "gstreamer-base", + "gstreamer-sys", + "libc", + "once_cell", ] [[package]] name = "gstreamer-app-sys" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "813f64275c9e7b33b828b9efcf9dfa64b95996766d4de996e84363ac65b87e3d" dependencies = [ - "glib-sys 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-base-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "system-deps 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys", + "gstreamer-base-sys", + "gstreamer-sys", + "libc", + "system-deps", ] [[package]] name = "gstreamer-base" version = "0.16.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bafd01c56f59cb10f4b5a10f97bb4bdf8c2b2784ae5b04da7e2d400cf6e6afcf" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "glib 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)", - "glib-sys 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gobject-sys 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer 0.16.5 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-base-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "glib", + "glib-sys", + "gobject-sys", + "gstreamer", + "gstreamer-base-sys", + "gstreamer-sys", + "libc", ] [[package]] name = "gstreamer-base-sys" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4b7b6dc2d6e160a1ae28612f602bd500b3fa474ce90bf6bb2f08072682beef5" dependencies = [ - "glib-sys 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gobject-sys 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "system-deps 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys", + "gobject-sys", + "gstreamer-sys", + "libc", + "system-deps", ] [[package]] name = "gstreamer-sys" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1f154082d01af5718c5f8a8eb4f565a4ea5586ad8833a8fc2c2aa6844b601d" dependencies = [ - "glib-sys 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gobject-sys 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "system-deps 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", ] [[package]] -name = "heck" -version = "0.3.1" +name = "h2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b67e66362108efccd8ac053abafc8b7a8d86a37e6e48fc4f6f7485eb5e9e6a5" dependencies = [ - "unicode-segmentation 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", + "tracing-futures", ] [[package]] -name = "hermit-abi" -version = "0.1.15" +name = "hashbrown" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" + +[[package]] +name = "heck" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-segmentation", ] [[package]] -name = "hex" -version = "0.4.2" +name = "hermit-abi" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +dependencies = [ + "libc", +] [[package]] name = "hmac" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" dependencies = [ - "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crypto-mac", + "digest", ] [[package]] -name = "hostname" -version = "0.3.1" +name = "http" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7245cd7449cc792608c3c8a9eaf69bd4eabbabf802713748fd739c98b82f0747" dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "match_cfg 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "fnv", + "itoa", ] [[package]] -name = "httparse" -version = "1.3.4" +name = "http-body" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2861bd27ee074e5ee891e8b539837a9430012e249d7f0ca2d795650f579c1994" +dependencies = [ + "bytes", + "http", +] [[package]] -name = "humantime" -version = "2.0.1" +name = "httparse" +version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" [[package]] -name = "hyper" -version = "0.11.27" +name = "httpdate" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "want 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47" [[package]] -name = "hyper-proxy" -version = "0.4.1" +name = "hyper" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12219dc884514cb4a6a03737f4413c0e01c23a1b059b0156004b23f1e19dccbe" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project 1.0.4", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", ] [[package]] name = "ident_case" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "matches", + "unicode-bidi", + "unicode-normalization", ] [[package]] name = "idna" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "matches", + "unicode-bidi", + "unicode-normalization", ] [[package]] -name = "if-addrs" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "if-addrs-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "if-addrs-sys" -version = "0.3.1" +name = "indexmap" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b" dependencies = [ - "cc 1.0.65 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", + "hashbrown", ] [[package]] name = "instant" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" dependencies = [ - "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "iovec" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", ] [[package]] name = "itertools" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" dependencies = [ - "either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "either", ] [[package]] name = "itoa" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" [[package]] name = "jack" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c1871c91fa65aa328f3bedbaa54a6e5d1de009264684c153eb708ba933aa6f5" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "jack-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "jack-sys", + "lazy_static", + "libc", ] [[package]] name = "jack-sys" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d6ab7ada402b6a27912a2b86504be62a48c58313c886fe72a059127acb4d7" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "libloading 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static", + "libc", + "libloading", ] [[package]] name = "jni" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1981310da491a4f0f815238097d0d43d8072732b5ae5f8bd0d8eadf5bf245402" dependencies = [ - "cesu8 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "combine 3.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "jni-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cesu8", + "combine 3.8.1", + "error-chain", + "jni-sys", + "log", + "walkdir", ] [[package]] name = "jni" version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36bcc950632e48b86da402c5c077590583da5ac0d480103611d5374e7c967a3c" dependencies = [ - "cesu8 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "combine 4.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "jni-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cesu8", + "combine 4.5.2", + "error-chain", + "jni-sys", + "log", + "walkdir", ] [[package]] name = "jni-sys" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "js-sys" version = "0.3.46" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d7383929f7c9c7c2d0fa596f325832df98c3704f2c60553080f7127a58175" dependencies = [ - "wasm-bindgen 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen", ] -[[package]] -name = "language-tags" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "lazycell" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "lewton" -version = "0.9.4" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "777b48df9aaab155475a83a7df3070395ea1ac6902f5cd062b8f2b028075c030" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ogg 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "ogg", + "tinyvec", ] [[package]] name = "libc" -version = "0.2.73" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929" [[package]] name = "libflate" -version = "0.1.27" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389de7875e06476365974da3e7ff85d55f1972188ccd9f6020dd7c8156e17914" dependencies = [ - "adler32 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crc32fast 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rle-decode-fast 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "adler32", + "crc32fast", + "libflate_lz77", + "rle-decode-fast", ] [[package]] -name = "libloading" -version = "0.4.3" +name = "libflate_lz77" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "3286f09f7d4926fc486334f28d8d2e6ebe4f7f9994494b6dab27ddfad2c9b11b" [[package]] name = "libloading" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.65 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libmdns" -version = "0.2.7" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "hostname 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "if-addrs 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "multimap 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "winapi", ] [[package]] name = "libpulse-binding" -version = "2.19.0" +version = "2.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce89ab17bd343b08bd4321c674ef1477d34f83be18b1ab2ee47a5e5fbee64a91" dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "libpulse-sys 1.15.3 (registry+https://github.com/rust-lang/crates.io-index)", - "num-derive 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "libc", + "libpulse-sys", + "num-derive", + "num-traits", + "winapi", ] [[package]] name = "libpulse-simple-binding" -version = "2.18.1" +version = "2.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e47f6cda2748fb86f15e5e65cc33be306577140f4b500622b5d98df2ca17240" dependencies = [ - "libpulse-binding 2.19.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libpulse-simple-sys 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libpulse-sys 1.15.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libpulse-binding", + "libpulse-simple-sys", + "libpulse-sys", ] [[package]] name = "libpulse-simple-sys" -version = "1.15.1" +version = "1.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "468cf582b7b022c0d1b266fefc7fc8fa7b1ddcb61214224f2f105c95a9c2d5c1" dependencies = [ - "libpulse-sys 1.15.3 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "libpulse-sys", + "pkg-config", ] [[package]] name = "libpulse-sys" -version = "1.15.3" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcfb56118765adba111da47e36278b77d00aebf822e4f014a832fbfa183a13b" dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "num-derive 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "num-derive", + "num-traits", + "pkg-config", + "winapi", ] [[package]] name = "librespot" version = "0.1.3" dependencies = [ - "base64 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)", - "librespot-audio 0.1.3", - "librespot-connect 0.1.3", - "librespot-core 0.1.3", - "librespot-metadata 0.1.3", - "librespot-playback 0.1.3", - "librespot-protocol 0.1.3", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "num-bigint 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rpassword 5.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sha-1 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-process 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-signal 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "librespot-audio", + "librespot-core", + "librespot-metadata", + "librespot-playback", + "librespot-protocol", ] [[package]] name = "librespot-audio" version = "0.1.3" dependencies = [ - "aes-ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bit-set 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "lewton 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)", - "librespot-core 0.1.3", - "librespot-tremor 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "num-bigint 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "vorbis 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "librespot-connect" -version = "0.1.3" -dependencies = [ - "aes-ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "base64 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "block-modes 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "dns-sd 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libmdns 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "librespot-core 0.1.3", - "librespot-playback 0.1.3", - "librespot-protocol 0.1.3", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "num-bigint 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", - "sha-1 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "aes-ctr", + "bit-set", + "byteorder", + "bytes", + "futures", + "lewton", + "librespot-core", + "librespot-tremor", + "log", + "num-bigint", + "num-traits", + "pin-project-lite", + "tempfile", + "vorbis", ] [[package]] name = "librespot-core" version = "0.1.3" dependencies = [ - "aes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "base64 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper-proxy 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "librespot-protocol 0.1.3", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "num-bigint 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", - "sha-1 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "shannon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "vergen 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "aes", + "base64 0.13.0", + "byteorder", + "bytes", + "futures", + "hmac", + "httparse", + "hyper", + "librespot-protocol", + "log", + "num-bigint", + "num-integer", + "num-traits", + "once_cell", + "pbkdf2", + "pin-project-lite", + "protobuf", + "rand 0.7.3", + "serde", + "serde_derive", + "serde_json", + "sha-1", + "shannon", + "tokio", + "tokio-util", + "url 1.7.2", + "uuid", + "vergen", ] [[package]] name = "librespot-metadata" version = "0.1.3" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "librespot-core 0.1.3", - "librespot-protocol 0.1.3", - "linear-map 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "async-trait", + "byteorder", + "futures", + "librespot-core", + "librespot-protocol", + "linear-map", + "log", + "protobuf", ] [[package]] name = "librespot-playback" version = "0.1.3" dependencies = [ - "alsa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cpal 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "glib 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer 0.16.5 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-app 0.16.5 (registry+https://github.com/rust-lang/crates.io-index)", - "jack 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "libpulse-binding 2.19.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libpulse-simple-binding 2.18.1 (registry+https://github.com/rust-lang/crates.io-index)", - "librespot-audio 0.1.3", - "librespot-core 0.1.3", - "librespot-metadata 0.1.3", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "portaudio-rs 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rodio 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sdl2 0.34.3 (registry+https://github.com/rust-lang/crates.io-index)", - "shell-words 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "zerocopy 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "alsa 0.2.2", + "byteorder", + "cpal", + "futures", + "glib", + "gstreamer", + "gstreamer-app", + "jack", + "libc", + "libpulse-binding", + "libpulse-simple-binding", + "librespot-audio", + "librespot-core", + "librespot-metadata", + "log", + "portaudio-rs", + "rodio", + "sdl2", + "shell-words", + "zerocopy", ] [[package]] name = "librespot-protocol" version = "0.1.3" dependencies = [ - "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf-codegen 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf-codegen-pure 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glob", + "protobuf", + "protobuf-codegen", + "protobuf-codegen-pure", ] [[package]] name = "librespot-tremor" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b155a7dc4e4d272e01c37a1b85c1ee1bee7f04980ad4a7784c1a6e0f2de5929b" dependencies = [ - "cc 1.0.65 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (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.18 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "libc", + "ogg-sys", + "pkg-config", ] [[package]] name = "linear-map" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "lock_api" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "bfae20f6b19ad527b550c223fddc3077a547fc70cda94b9b566575423fd303ee" [[package]] name = "lock_api" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312" dependencies = [ - "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "log" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard", ] [[package]] name = "log" -version = "0.4.11" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf3805d4480bb5b86070dcfeb9e2cb2ebc148adb753c5cca5f884d1d65a42b2" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10", ] [[package]] name = "mach" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] -[[package]] -name = "match_cfg" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "matches" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "maybe-uninit" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" [[package]] name = "memchr" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "memoffset" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mime" -version = "0.3.16" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" [[package]] name = "miniz_oxide" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" dependencies = [ - "adler 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "adler", + "autocfg", ] [[package]] name = "mio" -version = "0.6.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mio-named-pipes" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mio-uds" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miow" -version = "0.2.1" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e50ae3f04d169fcc9bde0b547d1c205219b7157e07ded9c5aff03e0637cb3ed7" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "log", + "miow", + "ntapi", + "winapi", ] [[package]] name = "miow" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897" dependencies = [ - "socket2 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "socket2", + "winapi", ] [[package]] name = "muldiv" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "multimap" -version = "0.8.1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "0419348c027fa7be448d2ae7ea0e4e04c2334c31dc4e74ab29f00a2a7ca69204" [[package]] name = "ndk" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb167c1febed0a496639034d0c76b3b74263636045db5489eee52143c246e73" dependencies = [ - "jni-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ndk-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num_enum 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "jni-sys", + "ndk-sys", + "num_enum", + "thiserror", ] [[package]] name = "ndk-glue" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdf399b8b7a39c6fb153c4ec32c72fd5fe789df24a647f229c239aa7adb15241" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "ndk 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ndk-macro 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ndk-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static", + "libc", + "log", + "ndk", + "ndk-macro", + "ndk-sys", ] [[package]] name = "ndk-macro" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d" dependencies = [ - "darling 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-crate 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "darling", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "ndk-sys" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "net2" -version = "0.2.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "c44922cb3dbb1c70b5e5f443d63b64363a898564d739ba5198e3a9138442868d" [[package]] name = "nix" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2c5afeb0198ec7be8569d666644b574345aad2e95a53baf3a532da3e0f3fb32" dependencies = [ - "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 0.9.1", + "cfg-if 0.1.10", + "libc", + "void", ] [[package]] name = "nix" version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.65 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "cc", + "cfg-if 0.1.10", + "libc", + "void", ] [[package]] name = "nom" version = "5.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" dependencies = [ - "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr", + "version_check", +] + +[[package]] +name = "ntapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +dependencies = [ + "winapi", ] [[package]] name = "num-bigint" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e9a41747ae4633fce5adffb4d2e81ffc5e89593cb19917f8fb2cc5ff76507bf" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", + "num-integer", + "num-traits", ] [[package]] name = "num-derive" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "num-integer" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", + "num-traits", ] [[package]] name = "num-rational" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", + "num-integer", + "num-traits", ] [[package]] name = "num-traits" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", ] [[package]] name = "num_cpus" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" dependencies = [ - "hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi", + "libc", ] [[package]] name = "num_enum" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca565a7df06f3d4b485494f25ba05da1435950f4dc263440eda7a6fa9b8e36e4" dependencies = [ - "derivative 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num_enum_derive 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "derivative", + "num_enum_derive", ] [[package]] name = "num_enum_derive" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffa5a33ddddfee04c0283a7653987d634e880347e96b5b2ed64de07efb59db9d" dependencies = [ - "proc-macro-crate 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "object" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4" [[package]] name = "oboe" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aadc2b0867bdbb9a81c4d99b9b682958f49dbea1295a81d2f646cca2afdd9fc" dependencies = [ - "jni 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ndk 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ndk-glue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-derive 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "oboe-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jni 0.14.0", + "ndk", + "ndk-glue", + "num-derive", + "num-traits", + "oboe-sys", ] [[package]] name = "oboe-sys" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ff7a51600eabe34e189eec5c995a62f151d8d97e5fbca39e87ca738bb99b82" dependencies = [ - "fetch_unroll 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "fetch_unroll", ] [[package]] name = "ogg" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6951b4e8bf21c8193da321bcce9c9dd2e13c858fe078bf9054a288b419ae5d6e" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", ] [[package]] name = "ogg-sys" version = "0.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a95b8c172e17df1a41bf8d666301d3b2c4efeb90d9d0415e2a4dc0668b35fdb2" dependencies = [ - "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc", + "libc", + "pkg-config", ] [[package]] name = "once_cell" version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" [[package]] name = "opaque-debug" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" [[package]] -name = "parking_lot" -version = "0.9.0" +name = "opaque-debug" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lock_api 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "parking_lot" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" dependencies = [ - "instant 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "lock_api 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "instant", + "lock_api", + "parking_lot_core", ] [[package]] name = "parking_lot_core" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ccb628cad4f84851442432c60ad8e1f607e29752d0bf072cbd0baf28aa34272" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cloudabi 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "instant 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall 0.1.57", + "smallvec", + "winapi", ] [[package]] name = "paste" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5d65c4d95931acda4498f675e332fcbdc9a06705cd07086c510e9b6009cd1c1" [[package]] name = "pbkdf2" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" dependencies = [ - "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.9.3", + "byteorder", + "crypto-mac", + "hmac", + "rand 0.5.6", + "sha2", + "subtle", ] [[package]] name = "peeking_take_while" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "percent-encoding" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" [[package]] name = "percent-encoding" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pin-project" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ffbc8e94b38ea3d2d8ba92aea2983b503cd75d0888d75b86bb37970b5698e15" +dependencies = [ + "pin-project-internal 0.4.27", +] [[package]] name = "pin-project" -version = "0.4.22" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b70b68509f17aa2857863b6fa00bf21fc93674c7a8893de2f469f6aa7ca2f2" dependencies = [ - "pin-project-internal 0.4.22 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project-internal 1.0.4", ] [[package]] name = "pin-project-internal" -version = "0.4.22" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65ad2ae56b6abe3a1ee25f15ee605bacadb9a764edaba9c2bf4103800d4a1895" dependencies = [ - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa25a6393f22ce819b0f50e0be89287292fda8d425be38ee0ca14c4931d9e71" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] name = "pin-project-lite" -version = "0.1.11" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827" [[package]] name = "pin-utils" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" [[package]] name = "portaudio-rs" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb6b5eff96ccc9bf44d34c379ab03ae944426d83d1694345bdf8159d561d562" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "portaudio-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "libc", + "portaudio-sys", ] [[package]] name = "portaudio-sys" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5194a4fa953b4ffd851c320ef6f0484cd7278cb7169ea9d6c433e49b23f7b7f5" dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "pkg-config", ] [[package]] name = "ppv-lite86" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "pretty-hex" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5c99d529f0d30937f6f4b8a86d988047327bb88d04d2c4afc356de74722131" [[package]] name = "proc-macro-crate" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" dependencies = [ - "toml 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", + "toml", ] [[package]] name = "proc-macro-error" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ - "proc-macro-error-attr 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", ] [[package]] name = "proc-macro-error-attr" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "version_check", ] [[package]] name = "proc-macro-hack" -version = "0.5.16" +version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro-nested" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" [[package]] name = "proc-macro2" -version = "1.0.19" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" dependencies = [ - "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid", ] [[package]] name = "protobuf" version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e86d370532557ae7573551a1ec8235a0f8d6cb276c7c9e6aa490b511c447485" [[package]] name = "protobuf-codegen" version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de113bba758ccf2c1ef816b127c958001b7831136c9bc3f8e9ec695ac4e82b0c" dependencies = [ - "protobuf 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf", ] [[package]] name = "protobuf-codegen-pure" version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d1a4febc73bf0cada1d77c459a0c8e5973179f1cfd5b0f1ab789d45b17b6440" dependencies = [ - "protobuf 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf-codegen 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf", + "protobuf-codegen", ] [[package]] -name = "qstring" -version = "0.7.2" +name = "publicsuffix" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bbaa49075179162b49acac1c6aa45fb4dafb5f13cf6794276d77bc7fd95757b" dependencies = [ - "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain", + "idna 0.2.0", + "lazy_static", + "regex", + "url 2.2.0", ] [[package]] -name = "quick-error" -version = "1.2.3" +name = "qstring" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" +dependencies = [ + "percent-encoding 2.1.0", +] [[package]] name = "quote" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" dependencies = [ - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", ] [[package]] name = "rand" -version = "0.3.23" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "winapi", ] [[package]] name = "rand" -version = "0.4.6" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc 0.2.0", ] [[package]] name = "rand" -version = "0.5.6" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18519b42a40024d661e1714153e9ad0c3de27cd495760ceb09710920f1098b1e" dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "rand_chacha 0.3.0", + "rand_core 0.6.1", + "rand_hc 0.3.0", ] [[package]] -name = "rand" -version = "0.7.3" +name = "rand_chacha" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" dependencies = [ - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86", + "rand_core 0.5.1", ] [[package]] name = "rand_chacha" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" dependencies = [ - "ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86", + "rand_core 0.6.1", ] [[package]] name = "rand_core" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" dependencies = [ - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2", ] [[package]] name = "rand_core" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" [[package]] name = "rand_core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5" dependencies = [ - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.2.2", ] [[package]] name = "rand_hc" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" dependencies = [ - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1", ] [[package]] -name = "rdrand" -version = "0.4.0" +name = "rand_hc" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.6.1", ] [[package]] name = "redox_syscall" version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" [[package]] -name = "regex" -version = "1.3.9" +name = "redox_syscall" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570" dependencies = [ - "regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", ] [[package]] -name = "regex-syntax" -version = "0.6.18" +name = "regex" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a" +dependencies = [ + "regex-syntax", +] [[package]] -name = "relay" -version = "0.1.1" +name = "regex-syntax" +version = "0.6.22" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581" [[package]] name = "remove_dir_all" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" dependencies = [ - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi", ] [[package]] name = "ring" -version = "0.16.18" +version = "0.16.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "024a1e66fea74c66c66624ee5622a7ff0e4b73a13b4f5c326ddb50c708944226" dependencies = [ - "cc 1.0.65 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "once_cell 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "web-sys 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", ] [[package]] name = "rle-decode-fast" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac" [[package]] name = "rodio" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9683532495146e98878d4948fa1a1953f584cd923f2a5f5c26b7a8701b56943" dependencies = [ - "cpal 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rpassword" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cpal", ] [[package]] name = "rustc-demangle" version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232" [[package]] name = "rustc-hash" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc_version" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "semver", ] [[package]] name = "rustls" -version = "0.16.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "064fd21ff87c6e87ed4506e68beb42459caa4a0e2eb144932e6776768556980b" dependencies = [ - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.16.18 (registry+https://github.com/rust-lang/crates.io-index)", - "sct 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki 0.21.3 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.13.0", + "log", + "ring", + "sct", + "webpki", ] [[package]] name = "ryu" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "safemem" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" [[package]] name = "same-file" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" dependencies = [ - "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util", ] -[[package]] -name = "scoped-tls" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "scopeguard" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "sct" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3042af939fca8c3453b7af0f1c66e533a15a86169e39de2657310ade8f98d3c" dependencies = [ - "ring 0.16.18 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ring", + "untrusted", ] [[package]] name = "sdl2" version = "0.34.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcbb85f4211627a7291c83434d6bbfa723e28dcaa53c7606087e3c61929e4b9c" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "sdl2-sys 0.34.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "lazy_static", + "libc", + "sdl2-sys", ] [[package]] name = "sdl2-sys" version = "0.34.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d81feded049b9c14eceb4a4f6d596a98cebbd59abdba949c5552a015466d33" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "version-compare 0.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10", + "libc", + "version-compare", ] [[package]] name = "semver" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "semver-parser", ] [[package]] name = "semver-parser" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.114" +version = "1.0.120" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "166b2349061381baf54a58e4b13c89369feb0ef2eaa57198899e2312aac30aab" +dependencies = [ + "serde_derive", +] [[package]] name = "serde_derive" -version = "1.0.114" +version = "1.0.120" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca2a8cb5805ce9e3b95435e3765b7b553cecc762d938d409434338386cb5775" dependencies = [ - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "serde_json" -version = "1.0.56" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a" dependencies = [ - "itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa", + "ryu", + "serde", ] [[package]] name = "sha-1" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" dependencies = [ - "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "block-buffer", + "digest", + "fake-simd", + "opaque-debug 0.2.3", ] +[[package]] +name = "sha1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" + [[package]] name = "sha2" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" dependencies = [ - "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "block-buffer", + "digest", + "fake-simd", + "opaque-debug 0.2.3", ] [[package]] name = "shannon" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ea5b41c9427b56caa7b808cb548a04fb50bb5b9e98590b53f28064ff4174561" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", ] [[package]] name = "shell-words" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fa3938c99da4914afedd13bf3d79bcb6c277d1b2c398d23257a304d9e1b074" [[package]] name = "shlex" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "signal-hook-registry" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arc-swap 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "slab" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" [[package]] name = "slab" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" [[package]] name = "smallvec" -version = "0.2.1" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] -name = "smallvec" -version = "0.6.13" +name = "socket2" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" dependencies = [ - "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "libc", + "winapi", ] [[package]] -name = "smallvec" -version = "1.5.0" +name = "spin" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] -name = "socket2" -version = "0.3.12" +name = "standback" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66a8cff4fa24853fdf6b51f75c6d7f8206d7c75cab4e467bcd7f25c2b1febe0" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check", ] [[package]] -name = "spin" -version = "0.5.2" +name = "stdweb" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e" [[package]] name = "stdweb" -version = "0.1.3" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" +dependencies = [ + "discard", + "rustc_version", + "stdweb-derive", + "stdweb-internal-macros", + "stdweb-internal-runtime", + "wasm-bindgen", +] + +[[package]] +name = "stdweb-derive" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "serde_derive", + "syn", +] [[package]] -name = "stream-cipher" -version = "0.3.2" +name = "stdweb-internal-macros" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" dependencies = [ - "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "base-x", + "proc-macro2", + "quote", + "serde", + "serde_derive", + "serde_json", + "sha1", + "syn", ] +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" + [[package]] name = "strsim" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" [[package]] name = "strum" version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b" [[package]] name = "strum_macros" version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c" dependencies = [ - "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "heck", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "subtle" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" [[package]] name = "syn" -version = "1.0.35" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc60a3d73ea6594cd712d830cc1f0390fd71542d8c8cd24e70cc54cdfd5e05d5" dependencies = [ - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "unicode-xid", ] [[package]] name = "synstructure" version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" dependencies = [ - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", + "unicode-xid", ] [[package]] name = "system-deps" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3ecc17269a19353b3558b313bba738b25d82993e30d62a18406a24aba4649b" dependencies = [ - "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "strum 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", - "strum_macros 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", - "version-compare 0.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "heck", + "pkg-config", + "strum", + "strum_macros", + "thiserror", + "toml", + "version-compare", ] -[[package]] -name = "take" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "take_mut" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "tar" version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "489997b7557e9a43e192c527face4feacc78bfbe6eed67fd55c4c9e381cba290" dependencies = [ - "filetime 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", - "xattr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime", + "libc", + "redox_syscall 0.1.57", + "xattr", ] [[package]] name = "tempfile" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "termcolor" -version = "1.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ - "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "libc", + "rand 0.8.2", + "redox_syscall 0.2.4", + "remove_dir_all", + "winapi", ] [[package]] name = "thiserror" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76cc616c6abf8c8928e2fdcc0dbfab37175edd8fb49a4641066ad1364fdab146" dependencies = [ - "thiserror-impl 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1" dependencies = [ - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "time" version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tinyvec" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "tokio" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-current-thread 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-fs 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-sync 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-udp 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-uds 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-codec" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-core" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)", - "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-current-thread" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-executor" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "winapi", ] [[package]] -name = "tokio-fs" -version = "0.1.7" +name = "time" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "273d3ed44dca264b0d6b3665e8d48fb515042d42466fad93d2a45b90ec4058f7" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "const_fn", + "libc", + "standback", + "stdweb 0.4.20", + "time-macros", + "version_check", + "winapi", ] [[package]] -name = "tokio-io" -version = "0.1.13" +name = "time-macros" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack", + "time-macros-impl", ] [[package]] -name = "tokio-process" -version = "0.2.5" +name = "time-macros-impl" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5c3be1edfad6027c69f5491cf4cb310d1a71ecd6af742788c6ff8bced86b8fa" dependencies = [ - "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)", - "mio-named-pipes 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-signal 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack", + "proc-macro2", + "quote", + "standback", + "syn", ] [[package]] -name = "tokio-proto" -version = "0.1.1" +name = "tinyvec" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf8dbc19eb42fba10e8feaaec282fb50e2c14b2726d6301dbfeed0f73306a6f" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tinyvec_macros", ] [[package]] -name = "tokio-reactor" -version = "0.1.12" +name = "tinyvec_macros" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-sync 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] -name = "tokio-service" -version = "0.1.0" +name = "tokio" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8efab2086f17abcddb8f756117665c958feee6b2e39974c2f1600592ab3a4195" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "pin-project-lite", + "tokio-macros", ] [[package]] -name = "tokio-signal" -version = "0.2.9" +name = "tokio-macros" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42517d2975ca3114b22a16192634e8241dc5cc1f130be194645970cc1c371494" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)", - "mio-uds 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "tokio-sync" -version = "0.1.8" +name = "tokio-stream" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76066865172052eb8796c686f0b441a93df8b08d40a950b062ffb9a426f00edd" dependencies = [ - "fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core", + "pin-project-lite", + "tokio", ] [[package]] -name = "tokio-tcp" -version = "0.1.4" +name = "tokio-util" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "feb971a26599ffd28066d387f109746df178eff14d5ea1e235015c5601967a4b" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "async-stream", + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", + "tokio-stream", ] [[package]] -name = "tokio-threadpool" -version = "0.1.18" +name = "toml" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" dependencies = [ - "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-queue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "serde", ] [[package]] -name = "tokio-timer" -version = "0.2.13" +name = "tower-service" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "e987b6bf443f4b5b3b6f38704195592cca41c5bb7aedd3c3693c7081f8289860" [[package]] -name = "tokio-udp" -version = "0.1.6" +name = "tracing" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f47026cdc4080c07e49b37087de021820269d996f581aac150ef9e5583eefe3" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "pin-project-lite", + "tracing-core", ] [[package]] -name = "tokio-uds" -version = "0.2.7" +name = "tracing-core" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)", - "mio-uds 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static", ] [[package]] -name = "toml" -version = "0.5.7" +name = "tracing-futures" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab7bb6f14721aa00656086e9335d363c5c8747bae02ebe32ea2c7dece5689b4c" dependencies = [ - "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project 0.4.27", + "tracing", ] [[package]] name = "try-lock" -version = "0.1.0" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "typenum" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicase" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" [[package]] name = "unicode-bidi" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "matches", ] [[package]] name = "unicode-normalization" -version = "0.1.13" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13e63ab62dbe32aeee58d1c5408d35c36c392bba5d9d3142287219721afe606" dependencies = [ - "tinyvec 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tinyvec", ] [[package]] name = "unicode-segmentation" version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicode-width" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" [[package]] name = "unicode-xid" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" [[package]] name = "unreachable" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" dependencies = [ - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "void", ] [[package]] name = "untrusted" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "ureq" -version = "0.11.4" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "294b85ef5dbc3670a72e82a89971608a1fcc4ed5c7c5a2895230d31a95f0569b" dependencies = [ - "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "chunked_transfer 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "qstring 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustls 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", - "url 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki 0.21.3 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki-roots 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.13.0", + "chunked_transfer", + "cookie", + "cookie_store", + "log", + "once_cell", + "qstring", + "rustls", + "url 2.2.0", + "webpki", + "webpki-roots", ] [[package]] name = "url" version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" dependencies = [ - "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "idna 0.1.5", + "matches", + "percent-encoding 1.0.1", ] [[package]] name = "url" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5909f2b0817350449ed73e8bcd81c8c3c8d9a7a5d8acba4b27db277f1868976e" dependencies = [ - "form_urlencoded 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "form_urlencoded", + "idna 0.2.0", + "matches", + "percent-encoding 2.1.0", ] [[package]] name = "uuid" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.2.2", ] [[package]] name = "vergen" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ce50d8996df1f85af15f2cd8d33daae6e479575123ef4314a51a70a230739cb" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "chrono 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "chrono", ] [[package]] name = "version-compare" version = "0.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1" [[package]] name = "version_check" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" [[package]] name = "void" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" [[package]] name = "vorbis" version = "0.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e8a194457075360557b82dac78f7ca2d65bbb6679bccfabae5f7c8c706cc776" dependencies = [ - "libc 0.2.73 (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.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "vorbisfile-sys 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "ogg-sys", + "vorbis-sys", + "vorbisfile-sys", ] [[package]] name = "vorbis-sys" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9ed6ef5361a85e68ccc005961d995c2d44e31f0816f142025f2ca2383dfbfd" dependencies = [ - "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (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.18 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "libc", + "ogg-sys", + "pkg-config", ] [[package]] name = "vorbisfile-sys" version = "0.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f4306d7e1ac4699b55e20de9483750b90c250913188efd7484db6bfbe9042d1" dependencies = [ - "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.73 (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.18 (registry+https://github.com/rust-lang/crates.io-index)", - "vorbis-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc", + "libc", + "ogg-sys", + "pkg-config", + "vorbis-sys", ] [[package]] name = "walkdir" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" dependencies = [ - "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "same-file", + "winapi", + "winapi-util", ] [[package]] name = "want" -version = "0.0.4" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "try-lock 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log", + "try-lock", ] [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.10.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93c6c3420963c5c64bca373b25e77acb562081b9bb4dd5bb864187742186cea9" [[package]] name = "wasm-bindgen" version = "0.2.69" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cd364751395ca0f68cafb17666eee36b63077fb5ecd972bbcd74c90c4bf736e" dependencies = [ - "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-macro 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.69" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1114f89ab1f4106e5b55e688b828c0ab0ea593a1ea7c094b141b14cbaaec2d62" dependencies = [ - "bumpalo 3.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-shared 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.69" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6ac8995ead1f084a8dea1e65f194d0973800c7f571f6edd70adf06ecf77084" dependencies = [ - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-macro-support 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "quote", + "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.69" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a48c72f299d80557c7c62e37e7225369ecc0c963964059509fbafe917c7549" dependencies = [ - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-backend 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-shared 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.69" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e7811dd7f9398f14cc76efd356f98f03aa30419dea46aa810d71e819fc97158" [[package]] name = "web-sys" version = "0.3.46" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222b1ef9334f92a21d3fb53dc3fd80f30836959a90f9274a626d7e06315ba3c3" dependencies = [ - "js-sys 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys", + "wasm-bindgen", ] [[package]] name = "webpki" -version = "0.21.3" +version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" dependencies = [ - "ring 0.16.18 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ring", + "untrusted", ] [[package]] name = "webpki-roots" -version = "0.18.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82015b7e0b8bad8185994674a13a93306bea76cf5a16c5a181382fd3a5ec2376" dependencies = [ - "webpki 0.21.3 (registry+https://github.com/rust-lang/crates.io-index)", + "webpki", ] -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "ws2_32-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "xattr" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" dependencies = [ - "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "zerocopy" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6580539ad917b7c026220c4b3f2c08d52ce54d6ce0dc491e66002e35388fab46" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "zerocopy-derive 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "zerocopy-derive", ] [[package]] name = "zerocopy-derive" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d498dbd1fd7beb83c86709ae1c33ca50942889473473d287d56ce4770a18edfb" dependencies = [ - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[metadata] -"checksum addr2line 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c0929d69e78dd9bf5408269919fcbcaeb2e35e5d43e5815517cdc6a8e11a423" -"checksum adler 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" -"checksum adler32 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" -"checksum aes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "54eb1d8fe354e5fc611daf4f2ea97dd45a765f4f1e4512306ec183ae2e8f20c9" -"checksum aes-ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2e5b0458ea3beae0d1d8c0f3946564f8e10f90646cf78c06b4351052058d1ee" -"checksum aes-soft 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cfd7e7ae3f9a1fb5c03b389fc6bb9a51400d0c13053f0dca698c832bfd893a0d" -"checksum aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100" -"checksum alsa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b4a0d4ebc8b23041c5de9bc9aee13b4bad844a589479701f31a5934cfe4aeb32" -"checksum alsa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "eb213f6b3e4b1480a60931ca2035794aa67b73103d254715b1db7b70dcb3c934" -"checksum alsa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b0edcbbf9ef68f15ae1b620f722180b82a98b6f0628d30baa6b8d2a5abc87d58" -"checksum alsa-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d5a0559bcd3f7a482690d98be41c08a43e92f669b179433e95ddf5e8b8fd36a3" -"checksum anyhow 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "2c0df63cb2955042487fad3aefd2c6e3ae7389ac5dc1beb28921de0b69f779d4" -"checksum arc-swap 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034" -"checksum ascii 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" -"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" -"checksum backtrace 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "ef5140344c85b01f9bbb4d4b7288a8aa4b3287ccef913a14bcc78a1063623598" -"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" -"checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" -"checksum base64 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" -"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" -"checksum bindgen 0.53.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c72a978d268b1d70b0e963217e60fdabd9523a941457a6c42a7315d15c7e89e5" -"checksum bit-set 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de" -"checksum bit-vec 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5f0dc55f2d8a1a85650ac47858bb001b4c0dd73d79e3c455a842925e68d29cd3" -"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" -"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -"checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774" -"checksum block-modes 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "31aa8410095e39fdb732909fb5730a48d5bd7c2e3cd76bd1b07b3dbea130c529" -"checksum block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" -"checksum bumpalo 3.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" -"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" -"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" -"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" -"checksum bytes 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" -"checksum cc 1.0.65 (registry+https://github.com/rust-lang/crates.io-index)" = "95752358c8f7552394baf48cd82695b345628ad3f170d607de3ca03b8dacca15" -"checksum cesu8 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" -"checksum cexpr 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" -"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -"checksum chrono 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "c74d84029116787153e02106bf53e66828452a4b325cc8652b788b5967c0a0b6" -"checksum chunked_transfer 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7477065d45a8fe57167bf3cf8bcd3729b54cfcb81cca49bda2d038ea89ae82ca" -"checksum clang-sys 0.29.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fe6837df1d5cba2397b835c8530f51723267e16abbf83892e9e5af4f0e5dd10a" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum cloudabi 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467" -"checksum combine 3.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" -"checksum combine 4.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b9417a0c314565e2abffaece67e95a8cb51f9238cd39f3764d9dfdf09e72b20c" -"checksum cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5" -"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" -"checksum coreaudio-rs 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f229761965dad3e9b11081668a6ea00f1def7aa46062321b5ec245b834f6e491" -"checksum coreaudio-sys 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d6570ee6e089131e928d5ec9236db9e818aa3cf850f48b0eec6ef700571271d4" -"checksum cpal 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05631e2089dfa5d3b6ea1cfbbfd092e2ee5deeb69698911bc976b28b746d3657" -"checksum crc32fast 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" -"checksum crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" -"checksum crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" -"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" -"checksum crossbeam-queue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" -"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" -"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" -"checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" -"checksum ctr 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "022cd691704491df67d25d006fe8eca083098253c4d43516c2206479c58c6736" -"checksum darling 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" -"checksum darling_core 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" -"checksum darling_macro 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" -"checksum derivative 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cb582b60359da160a9477ee80f15c8d784c477e69c217ef2cdd4169c24ea380f" -"checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -"checksum dns-sd 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d748509dea20228f63ba519bf142ce2593396386125b01f5b0d6412dab972087" -"checksum either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" -"checksum env_logger 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f26ecb66b4bdca6c1409b40fb255eefc2bd4f6d135dab3c3124f80ffa2a9661e" -"checksum error-chain 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d371106cc88ffdfb1eabd7111e432da544f16f3e2d7bf1dfe8bf575f1df045cd" -"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" -"checksum fetch_unroll 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b5c55005e95bbe15f5f72a73b6597d0dc82ddc97ffe2ca097a99dcd591fefbca" -"checksum filetime 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "0c122a393ea57648015bf06fbd3d372378992e86b9ff5a7a497b076a28c79efe" -"checksum fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -"checksum form_urlencoded 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef" -"checksum futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f366ad74c28cca6ba456d95e6422883cfb4b252a83bed929c83abfdbbf2967d5" -"checksum futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399" -"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" -"checksum futures-executor 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "10d6bb888be1153d3abeb9006b11b02cf5e9b209fda28693c31ae1e4e012e314" -"checksum futures-macro 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39" -"checksum futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f2032893cb734c7a05d85ce0cc8b8c4075278e93b24b66f9de99d6eb0fa8acc" -"checksum futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626" -"checksum futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6" -"checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" -"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" -"checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" -"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" -"checksum gimli 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" -"checksum glib 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0c685013b7515e668f1b57a165b009d4d28cb139a8a989bbd699c10dad29d0c5" -"checksum glib-macros 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "41486a26d1366a8032b160b59065a59fb528530a46a49f627e7048fb8c064039" -"checksum glib-sys 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7e9b997a66e9a23d073f2b1abb4dbfc3925e0b8952f67efd8d9b6e168e4cdc1" -"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" -"checksum gobject-sys 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "952133b60c318a62bf82ee75b93acc7e84028a093e06b9e27981c2b6fe68218c" -"checksum gstreamer 0.16.5 (registry+https://github.com/rust-lang/crates.io-index)" = "5d50f822055923f1cbede233aa5dfd4ee957cf328fb3076e330886094e11d6cf" -"checksum gstreamer-app 0.16.5 (registry+https://github.com/rust-lang/crates.io-index)" = "cc80888271338c3ede875d8cafc452eb207476ff5539dcbe0018a8f5b827af0e" -"checksum gstreamer-app-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "813f64275c9e7b33b828b9efcf9dfa64b95996766d4de996e84363ac65b87e3d" -"checksum gstreamer-base 0.16.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bafd01c56f59cb10f4b5a10f97bb4bdf8c2b2784ae5b04da7e2d400cf6e6afcf" -"checksum gstreamer-base-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a4b7b6dc2d6e160a1ae28612f602bd500b3fa474ce90bf6bb2f08072682beef5" -"checksum gstreamer-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fc1f154082d01af5718c5f8a8eb4f565a4ea5586ad8833a8fc2c2aa6844b601d" -"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" -"checksum hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" -"checksum hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" -"checksum hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" -"checksum hostname 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" -"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" -"checksum humantime 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3c1ad908cc71012b7bea4d0c53ba96a8cba9962f048fa68d143376143d863b7a" -"checksum hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)" = "34a590ca09d341e94cddf8e5af0bbccde205d5fbc2fa3c09dd67c7f85cea59d7" -"checksum hyper-proxy 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44f0925de2747e481e6e477dd212c25e8f745567f02f6182e04d27b97c3fbece" -"checksum ident_case 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" -"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" -"checksum if-addrs 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f12906406f12abf5569643c46b29aec78313dc1537b17dd5c5250169790c4db9" -"checksum if-addrs-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e2556f16544202bcfe0aa5d20a01a6b815f736b136b3ad76dc547ee6b5bb1df" -"checksum instant 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" -"checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" -"checksum itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" -"checksum itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" -"checksum jack 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7c1871c91fa65aa328f3bedbaa54a6e5d1de009264684c153eb708ba933aa6f5" -"checksum jack-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0d4ca501477fd3cd93a36df581046e5d6338ed826cf7e9b8d302603521e6cc3" -"checksum jni 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1981310da491a4f0f815238097d0d43d8072732b5ae5f8bd0d8eadf5bf245402" -"checksum jni 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "36bcc950632e48b86da402c5c077590583da5ac0d480103611d5374e7c967a3c" -"checksum jni-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" -"checksum js-sys 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d7383929f7c9c7c2d0fa596f325832df98c3704f2c60553080f7127a58175" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" -"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" -"checksum lewton 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8d542c1a317036c45c2aa1cf10cc9d403ca91eb2d333ef1a4917e5cb10628bd0" -"checksum libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)" = "bd7d4bd64732af4bf3a67f367c27df8520ad7e230c5817b8ff485864d80242b9" -"checksum libflate 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)" = "d9135df43b1f5d0e333385cb6e7897ecd1a43d7d11b91ac003f4d2c2d2401fdd" -"checksum libloading 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fd38073de8f7965d0c17d30546d4bb6da311ab428d1c7a3fc71dff7f9d4979b9" -"checksum libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" -"checksum libmdns 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5d8582c174736c53633bc482ac709b24527c018356c3dc6d8e25a788b06b394e" -"checksum libpulse-binding 2.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1e8f85a42300c868de4849bb72eda5a65cea08c3ca61396b72c2d7c28a87f055" -"checksum libpulse-simple-binding 2.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a047f4502997eed57b3e9d8e71f2b860da91a20bb7e15c65d1f183a7b4fb1226" -"checksum libpulse-simple-sys 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9b72cb239bc4de6858fa0bbad27419e72cd4466f079ca56f21d94b0a712ab02e" -"checksum libpulse-sys 1.15.3 (registry+https://github.com/rust-lang/crates.io-index)" = "706e95c4b87ebb81c1e7763c74bf7d5ba897208f1a8aa5fc7bea8298dee8f2ca" -"checksum librespot-tremor 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b155a7dc4e4d272e01c37a1b85c1ee1bee7f04980ad4a7784c1a6e0f2de5929b" -"checksum linear-map 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bfae20f6b19ad527b550c223fddc3077a547fc70cda94b9b566575423fd303ee" -"checksum lock_api 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" -"checksum lock_api 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312" -"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" -"checksum log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" -"checksum mach 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" -"checksum match_cfg 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" -"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" -"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" -"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" -"checksum memoffset 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c198b026e1bbf08a937e94c6c60f9ec4a2267f5b0d2eec9c1b21b061ce2be55f" -"checksum mime 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" -"checksum miniz_oxide 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" -"checksum mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)" = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430" -"checksum mio-named-pipes 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656" -"checksum mio-uds 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" -"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum miow 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "07b88fb9795d4d36d62a012dfbf49a8f5cf12751f36d31a9dbe66d528e58979e" -"checksum muldiv 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0419348c027fa7be448d2ae7ea0e4e04c2334c31dc4e74ab29f00a2a7ca69204" -"checksum multimap 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d8883adfde9756c1d30b0f519c9b8c502a94b41ac62f696453c37c7fc0a958ce" -"checksum ndk 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5eb167c1febed0a496639034d0c76b3b74263636045db5489eee52143c246e73" -"checksum ndk-glue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdf399b8b7a39c6fb153c4ec32c72fd5fe789df24a647f229c239aa7adb15241" -"checksum ndk-macro 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d" -"checksum ndk-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c44922cb3dbb1c70b5e5f443d63b64363a898564d739ba5198e3a9138442868d" -"checksum net2 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)" = "2ba7c918ac76704fb42afcbbb43891e72731f3dcca3bef2a19786297baf14af7" -"checksum nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229" -"checksum nix 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a2c5afeb0198ec7be8569d666644b574345aad2e95a53baf3a532da3e0f3fb32" -"checksum nom 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" -"checksum num-bigint 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e9a41747ae4633fce5adffb4d2e81ffc5e89593cb19917f8fb2cc5ff76507bf" -"checksum num-derive 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" -"checksum num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b" -"checksum num-rational 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" -"checksum num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" -"checksum num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" -"checksum num_enum 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca565a7df06f3d4b485494f25ba05da1435950f4dc263440eda7a6fa9b8e36e4" -"checksum num_enum_derive 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ffa5a33ddddfee04c0283a7653987d634e880347e96b5b2ed64de07efb59db9d" -"checksum object 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" -"checksum oboe 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1aadc2b0867bdbb9a81c4d99b9b682958f49dbea1295a81d2f646cca2afdd9fc" -"checksum oboe-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "68ff7a51600eabe34e189eec5c995a62f151d8d97e5fbca39e87ca738bb99b82" -"checksum ogg 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d79f1db9148be9d0e174bb3ac890f6030fcb1ed947267c5a91ee4c91b5a91e15" -"checksum ogg-sys 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "a95b8c172e17df1a41bf8d666301d3b2c4efeb90d9d0415e2a4dc0668b35fdb2" -"checksum once_cell 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" -"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" -"checksum parking_lot 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" -"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" -"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" -"checksum parking_lot_core 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b" -"checksum paste 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c5d65c4d95931acda4498f675e332fcbdc9a06705cd07086c510e9b6009cd1c1" -"checksum pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" -"checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" -"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" -"checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" -"checksum pin-project 0.4.22 (registry+https://github.com/rust-lang/crates.io-index)" = "12e3a6cdbfe94a5e4572812a0201f8c0ed98c1c452c7b8563ce2276988ef9c17" -"checksum pin-project-internal 0.4.22 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0ffd45cf79d88737d7cc85bfd5d2894bee1139b356e616fe85dc389c61aaf7" -"checksum pin-project-lite 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c917123afa01924fc84bb20c4c03f004d9c38e5127e3c039bbf7f4b9c76a2f6b" -"checksum pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -"checksum pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "d36492546b6af1463394d46f0c834346f31548646f6ba10849802c9c9a27ac33" -"checksum portaudio-rs 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cdb6b5eff96ccc9bf44d34c379ab03ae944426d83d1694345bdf8159d561d562" -"checksum portaudio-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5194a4fa953b4ffd851c320ef6f0484cd7278cb7169ea9d6c433e49b23f7b7f5" -"checksum ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" -"checksum pretty-hex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5c99d529f0d30937f6f4b8a86d988047327bb88d04d2c4afc356de74722131" -"checksum proc-macro-crate 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" -"checksum proc-macro-error 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -"checksum proc-macro-error-attr 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -"checksum proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)" = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4" -"checksum proc-macro-nested 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" -"checksum proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12" -"checksum protobuf 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8e86d370532557ae7573551a1ec8235a0f8d6cb276c7c9e6aa490b511c447485" -"checksum protobuf-codegen 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de113bba758ccf2c1ef816b127c958001b7831136c9bc3f8e9ec695ac4e82b0c" -"checksum protobuf-codegen-pure 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d1a4febc73bf0cada1d77c459a0c8e5973179f1cfd5b0f1ab789d45b17b6440" -"checksum qstring 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" -"checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" -"checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" -"checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" -"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" -"checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" -"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -"checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" -"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)" = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" -"checksum regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" -"checksum regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)" = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" -"checksum relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1576e382688d7e9deecea24417e350d3062d97e32e45d70b1cde65994ff1489a" -"checksum remove_dir_all 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -"checksum ring 0.16.18 (registry+https://github.com/rust-lang/crates.io-index)" = "70017ed5c555d79ee3538fc63ca09c70ad8f317dcadc1adc2c496b60c22bb24f" -"checksum rle-decode-fast 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac" -"checksum rodio 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c9683532495146e98878d4948fa1a1953f584cd923f2a5f5c26b7a8701b56943" -"checksum rpassword 5.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d755237fc0f99d98641540e66abac8bc46a0652f19148ac9e21de2da06b326c9" -"checksum rustc-demangle 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232" -"checksum rustc-hash 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum rustls 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b25a18b1bf7387f0145e7f8324e700805aade3842dd3db2e74e4cdeb4677c09e" -"checksum ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" -"checksum safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" -"checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -"checksum scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28" -"checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -"checksum sct 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e3042af939fca8c3453b7af0f1c66e533a15a86169e39de2657310ade8f98d3c" -"checksum sdl2 0.34.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fcbb85f4211627a7291c83434d6bbfa723e28dcaa53c7606087e3c61929e4b9c" -"checksum sdl2-sys 0.34.3 (registry+https://github.com/rust-lang/crates.io-index)" = "28d81feded049b9c14eceb4a4f6d596a98cebbd59abdba949c5552a015466d33" -"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)" = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3" -"checksum serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)" = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e" -"checksum serde_json 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)" = "3433e879a558dde8b5e8feb2a04899cf34fdde1fafb894687e52105fc1162ac3" -"checksum sha-1 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" -"checksum sha2 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" -"checksum shannon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7ea5b41c9427b56caa7b808cb548a04fb50bb5b9e98590b53f28064ff4174561" -"checksum shell-words 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6fa3938c99da4914afedd13bf3d79bcb6c277d1b2c398d23257a304d9e1b074" -"checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" -"checksum signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94f478ede9f64724c5d173d7bb56099ec3e2d9fc2774aac65d34b8b890405f41" -"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23" -"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" -"checksum smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c8cbcd6df1e117c2210e13ab5109635ad68a929fcbb8964dc965b76cb5ee013" -"checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" -"checksum smallvec 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7acad6f34eb9e8a259d3283d1e8c1d34d7415943d4895f65cc73813c7396fc85" -"checksum socket2 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" -"checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" -"checksum stdweb 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e" -"checksum stream-cipher 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8131256a5896cabcf5eb04f4d6dacbe1aefda854b0d9896e09cb58829ec5638c" -"checksum strsim 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" -"checksum strum 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b" -"checksum strum_macros 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c" -"checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" -"checksum syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "fb7f4c519df8c117855e19dd8cc851e89eb746fe7a73f0157e0d95fdec5369b0" -"checksum synstructure 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" -"checksum system-deps 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0f3ecc17269a19353b3558b313bba738b25d82993e30d62a18406a24aba4649b" -"checksum take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b157868d8ac1f56b64604539990685fa7611d8fa9e5476cf0c02cf34d32917c5" -"checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" -"checksum tar 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "489997b7557e9a43e192c527face4feacc78bfbe6eed67fd55c4c9e381cba290" -"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" -"checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" -"checksum thiserror 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "318234ffa22e0920fe9a40d7b8369b5f649d490980cf7aadcf1eb91594869b42" -"checksum thiserror-impl 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "cae2447b6282786c3493999f40a9be2a6ad20cb8bd268b0a0dbf5a065535c0ab" -"checksum time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" -"checksum tinyvec 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "53953d2d3a5ad81d9f844a32f14ebb121f50b650cd59d0ee2a07cf13c617efed" -"checksum tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" -"checksum tokio-codec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "25b2998660ba0e70d18684de5d06b70b70a3a747469af9dea7618cc59e75976b" -"checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71" -"checksum tokio-current-thread 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b1de0e32a83f131e002238d7ccde18211c0a5397f60cbfffcb112868c2e0e20e" -"checksum tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "fb2d1b8f4548dbf5e1f7818512e9c406860678f29c300cdf0ebac72d1a3a1671" -"checksum tokio-fs 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "297a1206e0ca6302a0eed35b700d292b275256f596e2f3fea7729d5e629b6ff4" -"checksum tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" -"checksum tokio-process 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "382d90f43fa31caebe5d3bc6cfd854963394fff3b8cb59d5146607aaae7e7e43" -"checksum tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fbb47ae81353c63c487030659494b295f6cb6576242f907f203473b191b0389" -"checksum tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "09bc590ec4ba8ba87652da2068d150dcada2cfa2e07faae270a5e0409aa51351" -"checksum tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162" -"checksum tokio-signal 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c34c6e548f101053321cba3da7cbb87a610b85555884c41b07da2eb91aff12" -"checksum tokio-sync 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "edfe50152bc8164fcc456dab7891fa9bf8beaf01c5ee7e1dd43a397c3cf87dee" -"checksum tokio-tcp 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "98df18ed66e3b72e742f185882a9e201892407957e45fbff8da17ae7a7c51f72" -"checksum tokio-threadpool 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "df720b6581784c118f0eb4310796b12b1d242a7eb95f716a8367855325c25f89" -"checksum tokio-timer 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "93044f2d313c95ff1cb7809ce9a7a05735b012288a888b62d4434fd58c94f296" -"checksum tokio-udp 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a0b10e610b39c38b031a2fcab08e4b82f16ece36504988dcbd81dbba650d82" -"checksum tokio-uds 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ab57a4ac4111c8c9dbcf70779f6fc8bc35ae4b2454809febac840ad19bd7e4e0" -"checksum toml 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)" = "75cf45bb0bef80604d001caaec0d09da99611b3c0fd39d3080468875cdb65645" -"checksum try-lock 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee2aa4715743892880f70885373966c83d73ef1b0838a664ef0c76fffd35e7c2" -"checksum typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" -"checksum unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -"checksum unicode-normalization 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6fb19cf769fa8c6a80a162df694621ebeb4dafb606470b2b2fce0be40a98a977" -"checksum unicode-segmentation 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" -"checksum unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" -"checksum unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" -"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -"checksum untrusted 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" -"checksum ureq 0.11.4 (registry+https://github.com/rust-lang/crates.io-index)" = "801125e6d1ba6864cf3a5a92cfb2f0b0a3ee73e40602a0cd206ad2f3c040aa96" -"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" -"checksum url 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5909f2b0817350449ed73e8bcd81c8c3c8d9a7a5d8acba4b27db277f1868976e" -"checksum uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11" -"checksum vergen 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ce50d8996df1f85af15f2cd8d33daae6e479575123ef4314a51a70a230739cb" -"checksum version-compare 0.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1" -"checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" -"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum vorbis 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "5e8a194457075360557b82dac78f7ca2d65bbb6679bccfabae5f7c8c706cc776" -"checksum vorbis-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3a0a8d7034313748da1d84b0adfa501f83f9ec83250f37fbacfa92a3580327c4" -"checksum vorbisfile-sys 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "4f4306d7e1ac4699b55e20de9483750b90c250913188efd7484db6bfbe9042d1" -"checksum walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" -"checksum want 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a05d9d966753fa4b5c8db73fcab5eed4549cfe0e1e4e66911e5564a0085c35d1" -"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" -"checksum wasm-bindgen 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)" = "3cd364751395ca0f68cafb17666eee36b63077fb5ecd972bbcd74c90c4bf736e" -"checksum wasm-bindgen-backend 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)" = "1114f89ab1f4106e5b55e688b828c0ab0ea593a1ea7c094b141b14cbaaec2d62" -"checksum wasm-bindgen-macro 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6ac8995ead1f084a8dea1e65f194d0973800c7f571f6edd70adf06ecf77084" -"checksum wasm-bindgen-macro-support 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a48c72f299d80557c7c62e37e7225369ecc0c963964059509fbafe917c7549" -"checksum wasm-bindgen-shared 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)" = "7e7811dd7f9398f14cc76efd356f98f03aa30419dea46aa810d71e819fc97158" -"checksum web-sys 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)" = "222b1ef9334f92a21d3fb53dc3fd80f30836959a90f9274a626d7e06315ba3c3" -"checksum webpki 0.21.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ab146130f5f790d45f82aeeb09e55a256573373ec64409fc19a6fb82fb1032ae" -"checksum webpki-roots 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "91cd5736df7f12a964a5067a12c62fa38e1bd8080aff1f80bc29be7c80d19ab4" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" -"checksum xattr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" -"checksum zerocopy 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6580539ad917b7c026220c4b3f2c08d52ce54d6ce0dc491e66002e35388fab46" -"checksum zerocopy-derive 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d498dbd1fd7beb83c86709ae1c33ca50942889473473d287d56ce4770a18edfb" + "proc-macro2", + "syn", + "synstructure", +] diff --git a/Cargo.toml b/Cargo.toml index 6405ca89b..a7ef8ed4f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,49 +15,35 @@ edition = "2018" name = "librespot" path = "src/lib.rs" -[[bin]] -name = "librespot" -path = "src/main.rs" -doc = false +# [[bin]] +# name = "librespot" +# path = "src/main.rs" +# doc = false [dependencies.librespot-audio] path = "audio" version = "0.1.3" -[dependencies.librespot-connect] -path = "connect" -version = "0.1.3" + +# [dependencies.librespot-connect] +# path = "connect" +# version = "0.1.3" + [dependencies.librespot-core] path = "core" version = "0.1.3" + [dependencies.librespot-metadata] path = "metadata" version = "0.1.3" + [dependencies.librespot-playback] path = "playback" version = "0.1.3" + [dependencies.librespot-protocol] path = "protocol" version = "0.1.3" -[dependencies] -base64 = "0.13" -env_logger = {version = "0.8", default-features = false, features = ["termcolor","humantime","atty"]} -futures = "0.1" -getopts = "0.2" -hyper = "0.11" -log = "0.4" -num-bigint = "0.3" -protobuf = "~2.14.0" -rand = "0.7" -rpassword = "5.0" -tokio-core = "0.1" -tokio-io = "0.1" -tokio-process = "0.2" -tokio-signal = "0.2" -url = "1.7" -sha-1 = "0.8" -hex = "0.4" - [features] alsa-backend = ["librespot-playback/alsa-backend"] portaudio-backend = ["librespot-playback/portaudio-backend"] @@ -70,7 +56,7 @@ gstreamer-backend = ["librespot-playback/gstreamer-backend"] with-tremor = ["librespot-audio/with-tremor"] with-vorbis = ["librespot-audio/with-vorbis"] -with-dns-sd = ["librespot-connect/with-dns-sd"] +# with-dns-sd = ["librespot-connect/with-dns-sd"] default = ["librespot-playback/rodio-backend"] diff --git a/src/lib.rs b/src/lib.rs index 31bac3437..4304e187a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,4 @@ #![crate_name = "librespot"] -#![cfg_attr(feature = "cargo-clippy", allow(unused_io_amount))] pub extern crate librespot_audio as audio; // pub extern crate librespot_connect as connect; diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 4f80657e2..000000000 --- a/src/main.rs +++ /dev/null @@ -1,620 +0,0 @@ -use futures::sync::mpsc::UnboundedReceiver; -use futures::{Async, Future, Poll, Stream}; -use log::{error, info, trace, warn}; -use sha1::{Digest, Sha1}; -use std::env; -use std::io::{self, stderr, Write}; -use std::mem; -use std::path::PathBuf; -use std::process::exit; -use std::str::FromStr; -use std::time::Instant; -use tokio_core::reactor::{Core, Handle}; -use tokio_io::IoStream; -use url::Url; - -use librespot::core::authentication::{get_credentials, Credentials}; -use librespot::core::cache::Cache; -use librespot::core::config::{ConnectConfig, DeviceType, SessionConfig, VolumeCtrl}; -use librespot::core::session::Session; -use librespot::core::version; - -use librespot::connect::discovery::{discovery, DiscoveryStream}; -use librespot::connect::spirc::{Spirc, SpircTask}; -use librespot::playback::audio_backend::{self, Sink, BACKENDS}; -use librespot::playback::config::{Bitrate, PlayerConfig}; -use librespot::playback::mixer::{self, Mixer, MixerConfig}; -use librespot::playback::player::{Player, PlayerEvent}; - -mod player_event_handler; -use crate::player_event_handler::{emit_sink_event, run_program_on_events}; - -fn device_id(name: &str) -> String { - hex::encode(Sha1::digest(name.as_bytes())) -} - -fn usage(program: &str, opts: &getopts::Options) -> String { - let brief = format!("Usage: {} [options]", program); - opts.usage(&brief) -} - -fn setup_logging(verbose: bool) { - let mut builder = env_logger::Builder::new(); - match env::var("RUST_LOG") { - Ok(config) => { - builder.parse_filters(&config); - builder.init(); - - if verbose { - warn!("`--verbose` flag overidden by `RUST_LOG` environment variable"); - } - } - Err(_) => { - if verbose { - builder.parse_filters("libmdns=info,librespot=trace"); - } else { - builder.parse_filters("libmdns=info,librespot=info"); - } - builder.init(); - } - } -} - -fn list_backends() { - println!("Available Backends : "); - for (&(name, _), idx) in BACKENDS.iter().zip(0..) { - if idx == 0 { - println!("- {} (default)", name); - } else { - println!("- {}", name); - } - } -} - -#[derive(Clone)] -struct Setup { - backend: fn(Option) -> Box, - device: Option, - - mixer: fn(Option) -> Box, - - cache: Option, - player_config: PlayerConfig, - session_config: SessionConfig, - connect_config: ConnectConfig, - mixer_config: MixerConfig, - credentials: Option, - enable_discovery: bool, - zeroconf_port: u16, - player_event_program: Option, - emit_sink_events: bool, -} - -fn setup(args: &[String]) -> Setup { - let mut opts = getopts::Options::new(); - opts.optopt( - "c", - "cache", - "Path to a directory where files will be cached.", - "CACHE", - ).optopt( - "", - "system-cache", - "Path to a directory where system files (credentials, volume) will be cached. Can be different from cache option value", - "SYTEMCACHE", - ).optflag("", "disable-audio-cache", "Disable caching of the audio data.") - .reqopt("n", "name", "Device name", "NAME") - .optopt("", "device-type", "Displayed device type", "DEVICE_TYPE") - .optopt( - "b", - "bitrate", - "Bitrate (96, 160 or 320). Defaults to 160", - "BITRATE", - ) - .optopt( - "", - "onevent", - "Run PROGRAM when playback is about to begin.", - "PROGRAM", - ) - .optflag("", "emit-sink-events", "Run program set by --onevent before sink is opened and after it is closed.") - .optflag("v", "verbose", "Enable verbose output") - .optopt("u", "username", "Username to sign in with", "USERNAME") - .optopt("p", "password", "Password", "PASSWORD") - .optopt("", "proxy", "HTTP proxy to use when connecting", "PROXY") - .optopt("", "ap-port", "Connect to AP with specified port. If no AP with that port are present fallback AP will be used. Available ports are usually 80, 443 and 4070", "AP_PORT") - .optflag("", "disable-discovery", "Disable discovery mode") - .optopt( - "", - "backend", - "Audio backend to use. Use '?' to list options", - "BACKEND", - ) - .optopt( - "", - "device", - "Audio device to use. Use '?' to list options if using portaudio or alsa", - "DEVICE", - ) - .optopt("", "mixer", "Mixer to use (alsa or softvol)", "MIXER") - .optopt( - "m", - "mixer-name", - "Alsa mixer name, e.g \"PCM\" or \"Master\". Defaults to 'PCM'", - "MIXER_NAME", - ) - .optopt( - "", - "mixer-card", - "Alsa mixer card, e.g \"hw:0\" or similar from `aplay -l`. Defaults to 'default' ", - "MIXER_CARD", - ) - .optopt( - "", - "mixer-index", - "Alsa mixer index, Index of the cards mixer. Defaults to 0", - "MIXER_INDEX", - ) - .optflag( - "", - "mixer-linear-volume", - "Disable alsa's mapped volume scale (cubic). Default false", - ) - .optopt( - "", - "initial-volume", - "Initial volume in %, once connected (must be from 0 to 100)", - "VOLUME", - ) - .optopt( - "", - "zeroconf-port", - "The port the internal server advertised over zeroconf uses.", - "ZEROCONF_PORT", - ) - .optflag( - "", - "enable-volume-normalisation", - "Play all tracks at the same volume", - ) - .optopt( - "", - "normalisation-pregain", - "Pregain (dB) applied by volume normalisation", - "PREGAIN", - ) - .optopt( - "", - "volume-ctrl", - "Volume control type - [linear, log, fixed]. Default is logarithmic", - "VOLUME_CTRL" - ) - .optflag( - "", - "autoplay", - "autoplay similar songs when your music ends.", - ) - .optflag( - "", - "disable-gapless", - "disable gapless playback.", - ); - - let matches = match opts.parse(&args[1..]) { - Ok(m) => m, - Err(f) => { - writeln!( - stderr(), - "error: {}\n{}", - f.to_string(), - usage(&args[0], &opts) - ) - .unwrap(); - exit(1); - } - }; - - let verbose = matches.opt_present("verbose"); - setup_logging(verbose); - - info!( - "librespot {} ({}). Built on {}. Build ID: {}", - version::short_sha(), - version::commit_date(), - version::short_now(), - version::build_id() - ); - - let backend_name = matches.opt_str("backend"); - if backend_name == Some("?".into()) { - list_backends(); - exit(0); - } - - let backend = audio_backend::find(backend_name).expect("Invalid backend"); - - let device = matches.opt_str("device"); - if device == Some("?".into()) { - backend(device); - exit(0); - } - - let mixer_name = matches.opt_str("mixer"); - let mixer = mixer::find(mixer_name.as_ref()).expect("Invalid mixer"); - - let mixer_config = MixerConfig { - card: matches - .opt_str("mixer-card") - .unwrap_or(String::from("default")), - mixer: matches.opt_str("mixer-name").unwrap_or(String::from("PCM")), - index: matches - .opt_str("mixer-index") - .map(|index| index.parse::().unwrap()) - .unwrap_or(0), - mapped_volume: !matches.opt_present("mixer-linear-volume"), - }; - - let cache = matches.opt_str("c").map(|cache_path| { - let use_audio_cache = !matches.opt_present("disable-audio-cache"); - let system_cache_directory = matches - .opt_str("system-cache") - .unwrap_or(String::from(cache_path.clone())); - - Cache::new( - PathBuf::from(cache_path), - PathBuf::from(system_cache_directory), - use_audio_cache, - ) - }); - - let initial_volume = matches - .opt_str("initial-volume") - .map(|volume| { - let volume = volume.parse::().unwrap(); - if volume > 100 { - panic!("Initial volume must be in the range 0-100"); - } - (volume as i32 * 0xFFFF / 100) as u16 - }) - .or_else(|| cache.as_ref().and_then(Cache::volume)) - .unwrap_or(0x8000); - - let zeroconf_port = matches - .opt_str("zeroconf-port") - .map(|port| port.parse::().unwrap()) - .unwrap_or(0); - - let name = matches.opt_str("name").unwrap(); - - let credentials = { - let cached_credentials = cache.as_ref().and_then(Cache::credentials); - - let password = |username: &String| -> String { - write!(stderr(), "Password for {}: ", username).unwrap(); - stderr().flush().unwrap(); - rpassword::read_password().unwrap() - }; - - get_credentials( - matches.opt_str("username"), - matches.opt_str("password"), - cached_credentials, - password, - ) - }; - - let session_config = { - let device_id = device_id(&name); - - SessionConfig { - user_agent: version::version_string(), - device_id: device_id, - proxy: matches.opt_str("proxy").or(std::env::var("http_proxy").ok()).map( - |s| { - match Url::parse(&s) { - Ok(url) => { - if url.host().is_none() || url.port_or_known_default().is_none() { - panic!("Invalid proxy url, only urls on the format \"http://host:port\" are allowed"); - } - - if url.scheme() != "http" { - panic!("Only unsecure http:// proxies are supported"); - } - url - }, - Err(err) => panic!("Invalid proxy url: {}, only urls on the format \"http://host:port\" are allowed", err) - } - }, - ), - ap_port: matches - .opt_str("ap-port") - .map(|port| port.parse::().expect("Invalid port")), - } - }; - - let player_config = { - let bitrate = matches - .opt_str("b") - .as_ref() - .map(|bitrate| Bitrate::from_str(bitrate).expect("Invalid bitrate")) - .unwrap_or(Bitrate::default()); - PlayerConfig { - bitrate: bitrate, - gapless: !matches.opt_present("disable-gapless"), - normalisation: matches.opt_present("enable-volume-normalisation"), - normalisation_pregain: matches - .opt_str("normalisation-pregain") - .map(|pregain| pregain.parse::().expect("Invalid pregain float value")) - .unwrap_or(PlayerConfig::default().normalisation_pregain), - } - }; - - let connect_config = { - let device_type = matches - .opt_str("device-type") - .as_ref() - .map(|device_type| DeviceType::from_str(device_type).expect("Invalid device type")) - .unwrap_or(DeviceType::default()); - - let volume_ctrl = matches - .opt_str("volume-ctrl") - .as_ref() - .map(|volume_ctrl| VolumeCtrl::from_str(volume_ctrl).expect("Invalid volume ctrl type")) - .unwrap_or(VolumeCtrl::default()); - - ConnectConfig { - name: name, - device_type: device_type, - volume: initial_volume, - volume_ctrl: volume_ctrl, - autoplay: matches.opt_present("autoplay"), - } - }; - - let enable_discovery = !matches.opt_present("disable-discovery"); - - Setup { - backend: backend, - cache: cache, - session_config: session_config, - player_config: player_config, - connect_config: connect_config, - credentials: credentials, - device: device, - enable_discovery: enable_discovery, - zeroconf_port: zeroconf_port, - mixer: mixer, - mixer_config: mixer_config, - player_event_program: matches.opt_str("onevent"), - emit_sink_events: matches.opt_present("emit-sink-events"), - } -} - -struct Main { - cache: Option, - player_config: PlayerConfig, - session_config: SessionConfig, - connect_config: ConnectConfig, - backend: fn(Option) -> Box, - device: Option, - mixer: fn(Option) -> Box, - mixer_config: MixerConfig, - handle: Handle, - - discovery: Option, - signal: IoStream<()>, - - spirc: Option, - spirc_task: Option, - connect: Box>, - - shutdown: bool, - last_credentials: Option, - auto_connect_times: Vec, - - player_event_channel: Option>, - player_event_program: Option, - emit_sink_events: bool, -} - -impl Main { - fn new(handle: Handle, setup: Setup) -> Main { - let mut task = Main { - handle: handle.clone(), - cache: setup.cache, - session_config: setup.session_config, - player_config: setup.player_config, - connect_config: setup.connect_config, - backend: setup.backend, - device: setup.device, - mixer: setup.mixer, - mixer_config: setup.mixer_config, - - connect: Box::new(futures::future::empty()), - discovery: None, - spirc: None, - spirc_task: None, - shutdown: false, - last_credentials: None, - auto_connect_times: Vec::new(), - signal: Box::new(tokio_signal::ctrl_c().flatten_stream()), - - player_event_channel: None, - player_event_program: setup.player_event_program, - emit_sink_events: setup.emit_sink_events, - }; - - if setup.enable_discovery { - let config = task.connect_config.clone(); - let device_id = task.session_config.device_id.clone(); - - task.discovery = - Some(discovery(&handle, config, device_id, setup.zeroconf_port).unwrap()); - } - - if let Some(credentials) = setup.credentials { - task.credentials(credentials); - } - - task - } - - fn credentials(&mut self, credentials: Credentials) { - self.last_credentials = Some(credentials.clone()); - let config = self.session_config.clone(); - let handle = self.handle.clone(); - - let connection = Session::connect(config, credentials, self.cache.clone(), handle); - - self.connect = connection; - self.spirc = None; - let task = mem::replace(&mut self.spirc_task, None); - if let Some(task) = task { - self.handle.spawn(task); - } - } -} - -impl Future for Main { - type Item = (); - type Error = (); - - fn poll(&mut self) -> Poll<(), ()> { - loop { - let mut progress = false; - - if let Some(Async::Ready(Some(creds))) = - self.discovery.as_mut().map(|d| d.poll().unwrap()) - { - if let Some(ref spirc) = self.spirc { - spirc.shutdown(); - } - self.auto_connect_times.clear(); - self.credentials(creds); - - progress = true; - } - - match self.connect.poll() { - Ok(Async::Ready(session)) => { - self.connect = Box::new(futures::future::empty()); - let mixer_config = self.mixer_config.clone(); - let mixer = (self.mixer)(Some(mixer_config)); - let player_config = self.player_config.clone(); - let connect_config = self.connect_config.clone(); - - let audio_filter = mixer.get_audio_filter(); - let backend = self.backend; - let device = self.device.clone(); - let (player, event_channel) = - Player::new(player_config, session.clone(), audio_filter, move || { - (backend)(device) - }); - - if self.emit_sink_events { - if let Some(player_event_program) = &self.player_event_program { - let player_event_program = player_event_program.clone(); - player.set_sink_event_callback(Some(Box::new(move |sink_status| { - emit_sink_event(sink_status, &player_event_program) - }))); - } - } - - let (spirc, spirc_task) = Spirc::new(connect_config, session, player, mixer); - self.spirc = Some(spirc); - self.spirc_task = Some(spirc_task); - self.player_event_channel = Some(event_channel); - - progress = true; - } - Ok(Async::NotReady) => (), - Err(error) => { - error!("Could not connect to server: {}", error); - self.connect = Box::new(futures::future::empty()); - } - } - - if let Async::Ready(Some(())) = self.signal.poll().unwrap() { - trace!("Ctrl-C received"); - if !self.shutdown { - if let Some(ref spirc) = self.spirc { - spirc.shutdown(); - } else { - return Ok(Async::Ready(())); - } - self.shutdown = true; - } else { - return Ok(Async::Ready(())); - } - - progress = true; - } - - let mut drop_spirc_and_try_to_reconnect = false; - if let Some(ref mut spirc_task) = self.spirc_task { - if let Async::Ready(()) = spirc_task.poll().unwrap() { - if self.shutdown { - return Ok(Async::Ready(())); - } else { - warn!("Spirc shut down unexpectedly"); - drop_spirc_and_try_to_reconnect = true; - } - progress = true; - } - } - if drop_spirc_and_try_to_reconnect { - self.spirc_task = None; - while (!self.auto_connect_times.is_empty()) - && ((Instant::now() - self.auto_connect_times[0]).as_secs() > 600) - { - let _ = self.auto_connect_times.remove(0); - } - - if let Some(credentials) = self.last_credentials.clone() { - if self.auto_connect_times.len() >= 5 { - warn!("Spirc shut down too often. Not reconnecting automatically."); - } else { - self.auto_connect_times.push(Instant::now()); - self.credentials(credentials); - } - } - } - - if let Some(ref mut player_event_channel) = self.player_event_channel { - if let Async::Ready(Some(event)) = player_event_channel.poll().unwrap() { - progress = true; - if let Some(ref program) = self.player_event_program { - if let Some(child) = run_program_on_events(event, program) { - let child = child - .expect("program failed to start") - .map(|status| { - if !status.success() { - error!("child exited with status {:?}", status.code()); - } - }) - .map_err(|e| error!("failed to wait on child process: {}", e)); - - self.handle.spawn(child); - } - } - } - } - - if !progress { - return Ok(Async::NotReady); - } - } - } -} - -fn main() { - if env::var("RUST_BACKTRACE").is_err() { - env::set_var("RUST_BACKTRACE", "full") - } - let mut core = Core::new().unwrap(); - let handle = core.handle(); - - let args: Vec = std::env::args().collect(); - - core.run(Main::new(handle, setup(&args))).unwrap() -} From 07514c9dcca59bd13b149cd19a276fa27c6d6986 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Mon, 25 Jan 2021 20:55:49 +0100 Subject: [PATCH 21/75] Add proxy support to apresolve --- Cargo.lock | 46 +++++++++++++++++++++++++++++++++++++++++++ core/Cargo.toml | 1 + core/src/apresolve.rs | 25 +++++++++++------------ core/src/lib.rs | 1 + 4 files changed, 60 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5813a707c..3754fd69e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -962,6 +962,31 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" +[[package]] +name = "headers" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62689dc57c7456e69712607ffcbd0aa1dfcccf9af73727e9b25bc1825375cac3" +dependencies = [ + "base64 0.13.0", + "bitflags 1.2.1", + "bytes", + "headers-core", + "http", + "mime", + "sha-1", + "time 0.1.43", +] + +[[package]] +name = "headers-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +dependencies = [ + "http", +] + [[package]] name = "heck" version = "0.3.2" @@ -1047,6 +1072,20 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-proxy" +version = "0.8.0" +source = "git+https://github.com/e00E/hyper-proxy.git?branch=upgrade-tokio#4be706f2f0297bd3d14f301b6ea0be8f3078bb17" +dependencies = [ + "bytes", + "futures", + "headers", + "http", + "hyper", + "tokio", + "tower-service", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -1323,6 +1362,7 @@ dependencies = [ "hmac", "httparse", "hyper", + "hyper-proxy", "librespot-protocol", "log", "num-bigint", @@ -1452,6 +1492,12 @@ version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + [[package]] name = "miniz_oxide" version = "0.4.3" diff --git a/core/Cargo.toml b/core/Cargo.toml index c092c04d8..4ff469367 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -21,6 +21,7 @@ futures = { version = "0.3", features = ["bilock", "unstable"] } hmac = "0.7" httparse = "1.3" hyper = { version = "0.14", features = ["client", "tcp", "http1", "http2"] } +hyper-proxy = { git = "https://github.com/e00E/hyper-proxy.git", branch="upgrade-tokio", default_features = false } log = "0.4" num-bigint = "0.3" num-integer = "0.1" diff --git a/core/src/apresolve.rs b/core/src/apresolve.rs index 07c2958f4..d35b20912 100644 --- a/core/src/apresolve.rs +++ b/core/src/apresolve.rs @@ -1,7 +1,8 @@ const AP_FALLBACK: &'static str = "ap.spotify.com:443"; const APRESOLVE_ENDPOINT: &'static str = "http://apresolve.spotify.com/"; -use hyper::{Body, Client, Method, Request, Uri}; +use hyper::{client::HttpConnector, Body, Client, Method, Request, Uri}; +use hyper_proxy::{Intercept, Proxy, ProxyConnector}; use std::error::Error; use url::Url; @@ -13,7 +14,7 @@ pub struct APResolveData { async fn apresolve(proxy: &Option, ap_port: &Option) -> Result> { let port = ap_port.unwrap_or(443); - let req = Request::builder() + let mut req = Request::builder() .method(Method::GET) .uri( APRESOLVE_ENDPOINT @@ -22,26 +23,23 @@ async fn apresolve(proxy: &Option, ap_port: &Option) -> Result, ap_port: &Option) -> Result Date: Mon, 25 Jan 2021 20:56:22 +0100 Subject: [PATCH 22/75] Replaced .fold(0, add) by .sum() --- audio/src/range_set.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/audio/src/range_set.rs b/audio/src/range_set.rs index 8712dfd41..d01d888e7 100644 --- a/audio/src/range_set.rs +++ b/audio/src/range_set.rs @@ -54,7 +54,7 @@ impl RangeSet { } pub fn len(&self) -> usize { - self.ranges.iter().map(|r| r.length).fold(0, std::ops::Add::add) + self.ranges.iter().map(|r| r.length).sum() } pub fn get_range(&self, index: usize) -> Range { From a45fe85c27512b9d1a25b191731dc90103905f62 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Sat, 30 Jan 2021 13:53:44 +0100 Subject: [PATCH 23/75] Enable logging in test --- Cargo.lock | 61 +++++++++++++++++++++++++++++++++++++++++++ core/Cargo.toml | 1 + core/tests/connect.rs | 1 + 3 files changed, 63 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 3754fd69e..e41765183 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -64,6 +64,15 @@ dependencies = [ "opaque-debug 0.3.0", ] +[[package]] +name = "aho-corasick" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +dependencies = [ + "memchr", +] + [[package]] name = "alsa" version = "0.2.2" @@ -152,6 +161,17 @@ dependencies = [ "syn", ] +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.0.1" @@ -567,6 +587,19 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +[[package]] +name = "env_logger" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26ecb66b4bdca6c1409b40fb255eefc2bd4f6d135dab3c3124f80ffa2a9661e" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + [[package]] name = "error-chain" version = "0.12.4" @@ -1048,6 +1081,12 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "hyper" version = "0.14.2" @@ -1358,6 +1397,7 @@ dependencies = [ "base64 0.13.0", "byteorder", "bytes", + "env_logger", "futures", "hmac", "httparse", @@ -2172,7 +2212,10 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a" dependencies = [ + "aho-corasick", + "memchr", "regex-syntax", + "thread_local", ] [[package]] @@ -2598,6 +2641,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + [[package]] name = "thiserror" version = "1.0.23" @@ -2618,6 +2670,15 @@ dependencies = [ "syn", ] +[[package]] +name = "thread_local" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8208a331e1cb318dd5bd76951d2b8fc48ca38a69f5f4e4af1b6a9f8c6236915" +dependencies = [ + "once_cell", +] + [[package]] name = "time" version = "0.1.43" diff --git a/core/Cargo.toml b/core/Cargo.toml index 4ff469367..1f7b9afc5 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -46,4 +46,5 @@ rand = "0.7" vergen = "3.0.4" [dev-dependencies] +env_logger = "*" tokio = {version = "1.0", features = ["macros"] } \ No newline at end of file diff --git a/core/tests/connect.rs b/core/tests/connect.rs index 44d418a1f..4ea2a1fe5 100644 --- a/core/tests/connect.rs +++ b/core/tests/connect.rs @@ -7,6 +7,7 @@ mod tests { use apresolve::apresolve_or_fallback; #[tokio::test] async fn test_ap_resolve() { + env_logger::init(); let ap = apresolve_or_fallback(&None, &None).await; println!("AP: {:?}", ap); } From c1d62d72a7bd12f757d7d5b09b02b2c2387eda38 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Sat, 30 Jan 2021 14:03:34 +0100 Subject: [PATCH 24/75] Fixed ProxyTunnel --- core/src/proxytunnel.rs | 51 +++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/core/src/proxytunnel.rs b/core/src/proxytunnel.rs index 508de7f80..c8e9eab62 100644 --- a/core/src/proxytunnel.rs +++ b/core/src/proxytunnel.rs @@ -17,29 +17,40 @@ pub async fn connect( .into_bytes(); connection.write_all(buffer.as_ref()).await?; - buffer.clear(); - connection.read_to_end(&mut buffer).await?; - if buffer.is_empty() { - return Err(io::Error::new(io::ErrorKind::Other, "Early EOF from proxy")); - } + buffer.resize(buffer.capacity(), 0); + + let mut offset = 0; + loop { + let bytes_read = connection.read(&mut buffer[offset..]).await?; + if bytes_read == 0 { + return Err(io::Error::new(io::ErrorKind::Other, "Early EOF from proxy")); + } + offset += bytes_read; - let mut headers = [httparse::EMPTY_HEADER; 16]; - let mut response = httparse::Response::new(&mut headers); + let mut headers = [httparse::EMPTY_HEADER; 16]; + let mut response = httparse::Response::new(&mut headers); - response - .parse(&buffer[..]) - .map_err(|err| io::Error::new(io::ErrorKind::Other, err.to_string()))?; + let status = response + .parse(&buffer[..offset]) + .map_err(|err| io::Error::new(io::ErrorKind::Other, err))?; + + if status.is_complete() { + return match response.code { + Some(200) => Ok(connection), // Proxy says all is well + Some(code) => { + let reason = response.reason.unwrap_or("no reason"); + let msg = format!("Proxy responded with {}: {}", code, reason); + Err(io::Error::new(io::ErrorKind::Other, msg)) + } + None => Err(io::Error::new( + io::ErrorKind::Other, + "Malformed response from proxy", + )), + }; + } - match response.code { - Some(200) => Ok(connection), // Proxy says all is well - Some(code) => { - let reason = response.reason.unwrap_or("no reason"); - let msg = format!("Proxy responded with {}: {}", code, reason); - Err(io::Error::new(io::ErrorKind::Other, msg)) + if offset >= buffer.len() { + buffer.resize(buffer.len() * 2, 0); } - None => Err(io::Error::new( - io::ErrorKind::Other, - "Malformed response from proxy", - )), } } From bb44b99c92f16c2770651e75647a3e19cad8b77a Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Sat, 30 Jan 2021 14:45:31 +0100 Subject: [PATCH 25/75] Use proxytunnel in apresolve Implementing the tower_service::Service trait for a newly created ProxyTunnel struct, so it can be used as connector in hyper. --- Cargo.lock | 47 +--------------------- core/Cargo.toml | 2 +- core/src/apresolve.rs | 25 +++++------- core/src/connection/mod.rs | 18 ++++++++- core/src/lib.rs | 2 +- core/src/proxytunnel.rs | 82 ++++++++++++++++++++++++++++++-------- 6 files changed, 95 insertions(+), 81 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e41765183..7606ed82b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -995,31 +995,6 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" -[[package]] -name = "headers" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62689dc57c7456e69712607ffcbd0aa1dfcccf9af73727e9b25bc1825375cac3" -dependencies = [ - "base64 0.13.0", - "bitflags 1.2.1", - "bytes", - "headers-core", - "http", - "mime", - "sha-1", - "time 0.1.43", -] - -[[package]] -name = "headers-core" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" -dependencies = [ - "http", -] - [[package]] name = "heck" version = "0.3.2" @@ -1111,20 +1086,6 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-proxy" -version = "0.8.0" -source = "git+https://github.com/e00E/hyper-proxy.git?branch=upgrade-tokio#4be706f2f0297bd3d14f301b6ea0be8f3078bb17" -dependencies = [ - "bytes", - "futures", - "headers", - "http", - "hyper", - "tokio", - "tower-service", -] - [[package]] name = "ident_case" version = "1.0.1" @@ -1402,7 +1363,6 @@ dependencies = [ "hmac", "httparse", "hyper", - "hyper-proxy", "librespot-protocol", "log", "num-bigint", @@ -1420,6 +1380,7 @@ dependencies = [ "shannon", "tokio", "tokio-util", + "tower-service", "url 1.7.2", "uuid", "vergen", @@ -1532,12 +1493,6 @@ version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" -[[package]] -name = "mime" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" - [[package]] name = "miniz_oxide" version = "0.4.3" diff --git a/core/Cargo.toml b/core/Cargo.toml index 1f7b9afc5..e0d79527f 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -21,7 +21,6 @@ futures = { version = "0.3", features = ["bilock", "unstable"] } hmac = "0.7" httparse = "1.3" hyper = { version = "0.14", features = ["client", "tcp", "http1", "http2"] } -hyper-proxy = { git = "https://github.com/e00E/hyper-proxy.git", branch="upgrade-tokio", default_features = false } log = "0.4" num-bigint = "0.3" num-integer = "0.1" @@ -38,6 +37,7 @@ sha-1 = "~0.8" shannon = "0.2.0" tokio = { version = "1.0", features = ["io-util", "rt-multi-thread"] } tokio-util = { version = "0.6", features = ["codec"] } +tower-service = "0.3" url = "1.7" uuid = { version = "0.8", features = ["v4"] } diff --git a/core/src/apresolve.rs b/core/src/apresolve.rs index d35b20912..81340c9d4 100644 --- a/core/src/apresolve.rs +++ b/core/src/apresolve.rs @@ -1,11 +1,12 @@ const AP_FALLBACK: &'static str = "ap.spotify.com:443"; -const APRESOLVE_ENDPOINT: &'static str = "http://apresolve.spotify.com/"; +const APRESOLVE_ENDPOINT: &'static str = "http://apresolve.spotify.com:80"; -use hyper::{client::HttpConnector, Body, Client, Method, Request, Uri}; -use hyper_proxy::{Intercept, Proxy, ProxyConnector}; +use hyper::{Body, Client, Method, Request, Uri}; use std::error::Error; use url::Url; +use crate::proxytunnel::ProxyTunnel; + #[derive(Clone, Debug, Serialize, Deserialize)] pub struct APResolveData { ap_list: Vec, @@ -14,7 +15,7 @@ pub struct APResolveData { async fn apresolve(proxy: &Option, ap_port: &Option) -> Result> { let port = ap_port.unwrap_or(443); - let mut req = Request::builder() + let req = Request::builder() .method(Method::GET) .uri( APRESOLVE_ENDPOINT @@ -24,18 +25,10 @@ async fn apresolve(proxy: &Option, ap_port: &Option) -> Result; pub async fn connect(addr: String, proxy: &Option) -> io::Result { let socket = if let Some(proxy) = proxy { info!("Using proxy \"{}\"", proxy); + + let mut split = addr.rsplit(':'); + + let port = split + .next() + .unwrap() // will never panic, split iterator contains at least one element + .parse() + .map_err(|e| { + io::Error::new(io::ErrorKind::InvalidInput, format!("Invalid port: {}", e)) + })?; + + let host = split + .next() + .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Missing port"))?; + let socket_addr = proxy.to_socket_addrs().and_then(|mut iter| { iter.next().ok_or_else(|| { io::Error::new( @@ -31,7 +46,8 @@ pub async fn connect(addr: String, proxy: &Option) -> io::Result }) })?; let socket = TcpStream::connect(&socket_addr).await?; - proxytunnel::connect(socket, &addr).await? + + proxytunnel::connect(socket, host, port).await? } else { let socket_addr = addr.to_socket_addrs().and_then(|mut iter| { iter.next().ok_or_else(|| { diff --git a/core/src/lib.rs b/core/src/lib.rs index 4fb632a01..3e332c286 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -14,7 +14,6 @@ extern crate futures; extern crate hmac; extern crate httparse; extern crate hyper; -extern crate hyper_proxy; extern crate num_bigint; extern crate num_integer; extern crate num_traits; @@ -28,6 +27,7 @@ extern crate sha1; extern crate shannon; pub extern crate tokio; extern crate tokio_util; +extern crate tower_service; extern crate url; extern crate uuid; diff --git a/core/src/proxytunnel.rs b/core/src/proxytunnel.rs index c8e9eab62..c2033c851 100644 --- a/core/src/proxytunnel.rs +++ b/core/src/proxytunnel.rs @@ -1,27 +1,36 @@ -use std::io; - +use futures::Future; use hyper::Uri; -use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; +use std::{ + io, + net::{SocketAddr, ToSocketAddrs}, + pin::Pin, + task::Poll, +}; +use tokio::{ + io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}, + net::TcpStream, +}; +use tower_service::Service; pub async fn connect( - mut connection: T, - connect_url: &str, + mut proxy_connection: T, + connect_host: &str, + connect_port: u16, ) -> io::Result { - let uri = connect_url.parse::().unwrap(); - let mut buffer = format!( - "CONNECT {0}:{1} HTTP/1.1\r\n\ - \r\n", - uri.host().unwrap_or_else(|| panic!("No host in {}", uri)), - uri.port().unwrap_or_else(|| panic!("No port in {}", uri)) - ) - .into_bytes(); - connection.write_all(buffer.as_ref()).await?; + let mut buffer = Vec::new(); + buffer.extend_from_slice(b"CONNECT "); + buffer.extend_from_slice(connect_host.as_bytes()); + buffer.push(b':'); + buffer.extend_from_slice(connect_port.to_string().as_bytes()); + buffer.extend_from_slice(b" HTTP/1.1\r\n\r\n"); + + proxy_connection.write_all(buffer.as_ref()).await?; buffer.resize(buffer.capacity(), 0); let mut offset = 0; loop { - let bytes_read = connection.read(&mut buffer[offset..]).await?; + let bytes_read = proxy_connection.read(&mut buffer[offset..]).await?; if bytes_read == 0 { return Err(io::Error::new(io::ErrorKind::Other, "Early EOF from proxy")); } @@ -36,7 +45,7 @@ pub async fn connect( if status.is_complete() { return match response.code { - Some(200) => Ok(connection), // Proxy says all is well + Some(200) => Ok(proxy_connection), // Proxy says all is well Some(code) => { let reason = response.reason.unwrap_or("no reason"); let msg = format!("Proxy responded with {}: {}", code, reason); @@ -54,3 +63,44 @@ pub async fn connect( } } } + +#[derive(Clone)] +pub struct ProxyTunnel { + proxy_addr: SocketAddr, +} + +impl ProxyTunnel { + pub fn new(addr: T) -> io::Result { + let addr = addr.to_socket_addrs()?.next().ok_or_else(|| { + io::Error::new(io::ErrorKind::InvalidInput, "No socket address given") + })?; + Ok(Self { proxy_addr: addr }) + } +} + +impl Service for ProxyTunnel { + type Response = TcpStream; + type Error = io::Error; + type Future = Pin> + Send>>; + + fn poll_ready(&mut self, _: &mut std::task::Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn call(&mut self, url: Uri) -> Self::Future { + let proxy_addr = self.proxy_addr; + let fut = async move { + let host = url + .host() + .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Host is missing"))?; + let port = url + .port() + .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Port is missing"))?; + + let conn = TcpStream::connect(proxy_addr).await?; + connect(conn, host, port.as_u16()).await + }; + + Box::pin(fut) + } +} From 2f05ddfbc20fb04131a2ad1ce68dbc181fe6b7cf Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Fri, 12 Feb 2021 18:19:04 +0100 Subject: [PATCH 26/75] Fix bugs in player --- playback/src/player.rs | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/playback/src/player.rs b/playback/src/player.rs index b5683e55d..26eea7f23 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -327,15 +327,12 @@ impl Player { } pub async fn get_end_of_track_future(&self) { - self.get_player_event_channel() - .filter(|event| { - future::ready(matches!( - event, - PlayerEvent::EndOfTrack { .. } | PlayerEvent::Stopped { .. } - )) - }) - .for_each(|_| future::ready(())) - .await + let mut channel = self.get_player_event_channel(); + while let Some(event) = channel.next().await { + if matches!(event, PlayerEvent::EndOfTrack { .. } | PlayerEvent::Stopped { .. }) { + return; + } + } } pub fn set_sink_event_callback(&self, callback: Option) { @@ -676,14 +673,6 @@ impl PlayerTrackLoader { let bytes_per_second = self.stream_data_rate(format); let play_from_beginning = position_ms == 0; - let key = match self.session.audio_key().request(spotify_id, file_id).await { - Ok(key) => key, - Err(_) => { - error!("Unable to load decryption key"); - return None; - } - }; - // This is only a loop to be able to reload the file if an error occured // while opening a cached file. loop { @@ -712,6 +701,14 @@ impl PlayerTrackLoader { // we need to seek -> we set stream mode after the initial seek. stream_loader_controller.set_random_access_mode(); } + + let key = match self.session.audio_key().request(spotify_id, file_id).await { + Ok(key) => key, + Err(_) => { + error!("Unable to load decryption key"); + return None; + } + }; let mut decrypted_file = AudioDecrypt::new(key, encrypted_file); From b2f1be4374e091267d0676e92870b5f3eb30fa7c Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Fri, 12 Feb 2021 18:25:13 +0100 Subject: [PATCH 27/75] Make `RodioSink` `Send` and improve error handling --- Cargo.lock | 1 + playback/Cargo.toml | 9 ++- playback/src/audio_backend/rodio.rs | 111 ++++++++++++++++++---------- 3 files changed, 78 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6255e76c9..00343168f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1375,6 +1375,7 @@ dependencies = [ "rodio", "sdl2", "shell-words", + "thiserror", "zerocopy", ] diff --git a/playback/Cargo.toml b/playback/Cargo.toml index 95c4a12ac..156221986 100644 --- a/playback/Cargo.toml +++ b/playback/Cargo.toml @@ -29,19 +29,22 @@ libpulse-binding = { version = "2.13", optional = true, default-features libpulse-simple-binding = { version = "2.13", optional = true, default-features = false } jack = { version = "0.6", optional = true } libc = { version = "0.2", optional = true } -rodio = { version = "0.13", optional = true, default-features = false } -cpal = { version = "0.13", optional = true } sdl2 = { version = "0.34", optional = true } gstreamer = { version = "0.16", optional = true } gstreamer-app = { version = "0.16", optional = true } glib = { version = "0.10", optional = true } zerocopy = { version = "0.3", optional = true } +# Rodio dependencies +rodio = { version = "0.13", optional = true, default-features = false } +cpal = { version = "0.13", optional = true } +thiserror = { version = "1", optional = true } + [features] alsa-backend = ["alsa"] portaudio-backend = ["portaudio-rs"] pulseaudio-backend = ["libpulse-binding", "libpulse-simple-binding"] jackaudio-backend = ["jack"] -rodio-backend = ["rodio", "cpal"] +rodio-backend = ["rodio", "cpal", "thiserror"] sdl-backend = ["sdl2"] gstreamer-backend = ["gstreamer", "gstreamer-app", "glib", "zerocopy"] diff --git a/playback/src/audio_backend/rodio.rs b/playback/src/audio_backend/rodio.rs index bc1017867..0c4b1a420 100644 --- a/playback/src/audio_backend/rodio.rs +++ b/playback/src/audio_backend/rodio.rs @@ -1,20 +1,36 @@ -use super::{Open, Sink}; -extern crate cpal; -extern crate rodio; -use cpal::traits::{DeviceTrait, HostTrait}; use std::process::exit; +use std::{convert::Infallible, sync::mpsc}; use std::{io, thread, time}; +use cpal::traits::{DeviceTrait, HostTrait}; +use thiserror::Error; + +use super::{Open, Sink}; + +#[derive(Debug, Error)] +pub enum RodioError { + #[error("Rodio: no device available")] + NoDeviceAvailable, + #[error("Rodio: device \"{0}\" is not available")] + DeviceNotAvailable(String), + #[error("Rodio play error: {0}")] + PlayError(#[from] rodio::PlayError), + #[error("Rodio stream error: {0}")] + StreamError(#[from] rodio::StreamError), + #[error("Cannot get audio devices: {0}")] + DevicesError(#[from] cpal::DevicesError), +} + pub struct RodioSink { rodio_sink: rodio::Sink, - // We have to keep hold of this object, or the Sink can't play... - #[allow(dead_code)] - stream: rodio::OutputStream, + + // will produce a TryRecvError on the receiver side when it is dropped. + _close_tx: mpsc::SyncSender, } -fn list_formats(ref device: &rodio::Device) { +fn list_formats(device: &rodio::Device) { let default_fmt = match device.default_output_config() { - Ok(fmt) => cpal::SupportedStreamConfig::from(fmt), + Ok(fmt) => fmt, Err(e) => { warn!("Error getting default rodio::Sink config: {}", e); return; @@ -39,8 +55,8 @@ fn list_formats(ref device: &rodio::Device) { } } -fn list_outputs() { - let default_device = get_default_device(); +fn list_outputs_and_exit() -> ! { + let default_device = get_default_device().unwrap(); let default_device_name = default_device.name().expect("cannot get output name"); println!("Default Audio Device:\n {}", default_device_name); list_formats(&default_device); @@ -56,54 +72,69 @@ fn list_outputs() { list_formats(&device); } } + + exit(0) } -fn get_default_device() -> rodio::Device { +fn get_default_device() -> Result { cpal::default_host() .default_output_device() - .expect("no default output device available") + .ok_or(RodioError::NoDeviceAvailable) } -fn match_device(device: Option) -> rodio::Device { - match device { +fn create_sink(device: Option) -> Result<(rodio::Sink, rodio::OutputStream), RodioError> { + let rodio_device = match device { + Some(ask) if &ask == "?" => list_outputs_and_exit(), Some(device_name) => { - if device_name == "?".to_string() { - list_outputs(); - exit(0) - } - for d in cpal::default_host() - .output_devices() - .expect("cannot get list of output devices") - { - if d.name().expect("cannot get output name") == device_name { - return d; - } - } - println!("No output sink matching '{}' found.", device_name); - exit(0) + cpal::default_host() + .output_devices()? + .find(|d| d.name().ok().map_or(false, |name| name == device_name)) // Ignore devices for which getting name fails + .ok_or(RodioError::DeviceNotAvailable(device_name))? } - None => return get_default_device(), - } + None => get_default_device()?, + }; + + let name = rodio_device.name().ok(); + info!( + "Using audio device: {}", + name.as_deref().unwrap_or("(unknown name)") + ); + + let (stream, handle) = rodio::OutputStream::try_from_device(&rodio_device)?; + let sink = rodio::Sink::try_new(&handle)?; + Ok((sink, stream)) } impl Open for RodioSink { fn open(device: Option) -> RodioSink { debug!( "Using rodio sink with cpal host: {:?}", - cpal::default_host().id() + cpal::default_host().id().name() ); - let rodio_device = match_device(device); - debug!("Using cpal device"); - let stream = rodio::OutputStream::try_from_device(&rodio_device) - .expect("Couldn't open output stream."); - debug!("Using rodio stream"); - let sink = rodio::Sink::try_new(&stream.1).expect("Couldn't create output sink."); - debug!("Using rodio sink"); + let (sink_tx, sink_rx) = mpsc::sync_channel(1); + let (close_tx, close_rx) = mpsc::sync_channel(1); + + std::thread::spawn(move || match create_sink(device) { + Ok((sink, stream)) => { + sink_tx.send(Ok(sink)).unwrap(); + + close_rx.recv().unwrap_err(); // This will fail as soon as the sender is dropped + debug!("drop rodio::OutputStream"); + drop(stream); + } + Err(e) => { + sink_tx.send(Err(e)).unwrap(); + } + }); + + // Instead of the second `unwrap`, better error handling could be introduced + let sink = sink_rx.recv().unwrap().unwrap(); + debug!("Rodio sink was created"); RodioSink { rodio_sink: sink, - stream: stream.0, + _close_tx: close_tx, } } } From 689415a6f1580547dae5be592cb21a847114edb1 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Fri, 12 Feb 2021 19:31:41 +0100 Subject: [PATCH 28/75] Improved error handling in rodio backend --- playback/src/audio_backend/rodio.rs | 105 +++++++++++++++++----------- 1 file changed, 65 insertions(+), 40 deletions(-) diff --git a/playback/src/audio_backend/rodio.rs b/playback/src/audio_backend/rodio.rs index 0c4b1a420..034bd0866 100644 --- a/playback/src/audio_backend/rodio.rs +++ b/playback/src/audio_backend/rodio.rs @@ -29,75 +29,100 @@ pub struct RodioSink { } fn list_formats(device: &rodio::Device) { - let default_fmt = match device.default_output_config() { - Ok(fmt) => fmt, - Err(e) => { - warn!("Error getting default rodio::Sink config: {}", e); - return; + match device.default_output_config() { + Ok(cfg) => { + debug!(" Default config:"); + debug!(" {:?}", cfg); } - }; - debug!(" Default config:"); - debug!(" {:?}", default_fmt); - - let mut output_configs = match device.supported_output_configs() { - Ok(f) => f.peekable(), Err(e) => { - warn!("Error getting supported rodio::Sink configs: {}", e); - return; + // Use loglevel debug, since even the output is only debug + debug!("Error getting default rodio::Sink config: {}", e); } }; - if output_configs.peek().is_some() { - debug!(" Available configs:"); - for format in output_configs { - debug!(" {:?}", format); + match device.supported_output_configs() { + Ok(mut cfgs) => { + if let Some(first) = cfgs.next() { + debug!(" Available configs:"); + debug!(" {:?}", first); + } else { + return; + } + + for cfg in cfgs { + debug!(" {:?}", cfg); + } + } + Err(e) => { + debug!("Error getting supported rodio::Sink configs: {}", e); } } } -fn list_outputs_and_exit() -> ! { - let default_device = get_default_device().unwrap(); - let default_device_name = default_device.name().expect("cannot get output name"); - println!("Default Audio Device:\n {}", default_device_name); - list_formats(&default_device); - - println!("Other Available Audio Devices:"); - for device in cpal::default_host() - .output_devices() - .expect("cannot get list of output devices") - { - let device_name = device.name().expect("cannot get output name"); - if device_name != default_device_name { - println!(" {}", device_name); - list_formats(&device); +fn list_outputs() -> Result<(), cpal::DevicesError> { + let mut default_device_name = None; + + if let Some(default_device) = get_default_device() { + default_device_name = default_device.name().ok(); + println!( + "Default Audio Device:\n {}", + default_device_name.as_deref().unwrap_or("[unknown name]") + ); + + list_formats(&default_device); + + println!("Other Available Audio Devices:"); + } else { + warn!("No default device was found"); + } + + for device in cpal::default_host().output_devices()? { + match device.name() { + Ok(name) if Some(&name) == default_device_name.as_ref() => (), + Ok(name) => { + println!(" {}", name); + list_formats(&device); + } + Err(e) => { + warn!("Cannot get device name: {}", e); + println!(" [unknown name]"); + list_formats(&device); + } } } - exit(0) + Ok(()) } -fn get_default_device() -> Result { - cpal::default_host() - .default_output_device() - .ok_or(RodioError::NoDeviceAvailable) +fn get_default_device() -> Option { + cpal::default_host().default_output_device() } fn create_sink(device: Option) -> Result<(rodio::Sink, rodio::OutputStream), RodioError> { let rodio_device = match device { - Some(ask) if &ask == "?" => list_outputs_and_exit(), + Some(ask) if &ask == "?" => { + let exit_code = match list_outputs() { + Ok(()) => 0, + Err(e) => { + error!("{}", e); + 1 + } + }; + exit(exit_code) + } Some(device_name) => { cpal::default_host() .output_devices()? .find(|d| d.name().ok().map_or(false, |name| name == device_name)) // Ignore devices for which getting name fails .ok_or(RodioError::DeviceNotAvailable(device_name))? } - None => get_default_device()?, + None => get_default_device().ok_or(RodioError::NoDeviceAvailable)?, }; let name = rodio_device.name().ok(); info!( "Using audio device: {}", - name.as_deref().unwrap_or("(unknown name)") + name.as_deref().unwrap_or("[unknown name]") ); let (stream, handle) = rodio::OutputStream::try_from_device(&rodio_device)?; From b77f0a18cef0c893cb48d2b34746287c7c00cdc6 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Sat, 13 Feb 2021 10:29:00 +0100 Subject: [PATCH 29/75] Fix formatting --- core/src/connection/mod.rs | 2 +- playback/src/player.rs | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/core/src/connection/mod.rs b/core/src/connection/mod.rs index 1ca731657..68e2e7a50 100644 --- a/core/src/connection/mod.rs +++ b/core/src/connection/mod.rs @@ -32,7 +32,7 @@ pub async fn connect(addr: String, proxy: &Option) -> io::Result .map_err(|e| { io::Error::new(io::ErrorKind::InvalidInput, format!("Invalid port: {}", e)) })?; - + let host = split .next() .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Missing port"))?; diff --git a/playback/src/player.rs b/playback/src/player.rs index 26eea7f23..6f6a85aef 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -329,7 +329,10 @@ impl Player { pub async fn get_end_of_track_future(&self) { let mut channel = self.get_player_event_channel(); while let Some(event) = channel.next().await { - if matches!(event, PlayerEvent::EndOfTrack { .. } | PlayerEvent::Stopped { .. }) { + if matches!( + event, + PlayerEvent::EndOfTrack { .. } | PlayerEvent::Stopped { .. } + ) { return; } } @@ -701,7 +704,7 @@ impl PlayerTrackLoader { // we need to seek -> we set stream mode after the initial seek. stream_loader_controller.set_random_access_mode(); } - + let key = match self.session.audio_key().request(spotify_id, file_id).await { Ok(key) => key, Err(_) => { From daf7ecd23a26f124b91c915ee8f39cc3d30b0840 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Sat, 20 Feb 2021 00:17:18 +0100 Subject: [PATCH 30/75] Migrate librespot-connect to tokio 1.0 --- Cargo.lock | 321 +++++++++++++++++++++++++++++---------- Cargo.toml | 6 +- connect/Cargo.toml | 8 +- connect/src/discovery.rs | 125 ++++++--------- connect/src/spirc.rs | 304 +++++++++++++++++------------------- core/src/mercury/mod.rs | 60 ++++---- src/lib.rs | 2 +- 7 files changed, 467 insertions(+), 359 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 00343168f..6b6e7af24 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,21 +27,44 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" dependencies = [ - "aes-soft", - "aesni", + "aes-soft 0.6.4", + "aesni 0.10.0", "cipher", ] +[[package]] +name = "aes-ctr" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2e5b0458ea3beae0d1d8c0f3946564f8e10f90646cf78c06b4351052058d1ee" +dependencies = [ + "aes-soft 0.3.3", + "aesni 0.6.0", + "ctr 0.3.2", + "stream-cipher", +] + [[package]] name = "aes-ctr" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7729c3cde54d67063be556aeac75a81330d802f0259500ca40cb52967f975763" dependencies = [ - "aes-soft", - "aesni", + "aes-soft 0.6.4", + "aesni 0.10.0", "cipher", - "ctr", + "ctr 0.6.0", +] + +[[package]] +name = "aes-soft" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfd7e7ae3f9a1fb5c03b389fc6bb9a51400d0c13053f0dca698c832bfd893a0d" +dependencies = [ + "block-cipher-trait", + "byteorder", + "opaque-debug 0.2.3", ] [[package]] @@ -54,6 +77,17 @@ dependencies = [ "opaque-debug 0.3.0", ] +[[package]] +name = "aesni" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100" +dependencies = [ + "block-cipher-trait", + "opaque-debug 0.2.3", + "stream-cipher", +] + [[package]] name = "aesni" version = "0.10.0" @@ -223,6 +257,25 @@ dependencies = [ "generic-array 0.12.3", ] +[[package]] +name = "block-cipher-trait" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774" +dependencies = [ + "generic-array 0.12.3", +] + +[[package]] +name = "block-modes" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31aa8410095e39fdb732909fb5730a48d5bd7c2e3cd76bd1b07b3dbea130c529" +dependencies = [ + "block-cipher-trait", + "block-padding", +] + [[package]] name = "block-padding" version = "0.1.5" @@ -234,9 +287,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.6.0" +version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099e596ef14349721d9016f6b80dd3419ea1bf289ab9b44df8e4dfd3a005d5d9" +checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe" [[package]] name = "byte-tools" @@ -258,9 +311,9 @@ checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" [[package]] name = "cc" -version = "1.0.66" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" +checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" [[package]] name = "cesu8" @@ -384,13 +437,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3818dfca4b0cb5211a659bbcbb94225b7127407b2b135e650d717bfb78ab10d3" dependencies = [ "cookie", - "idna 0.2.1", + "idna 0.2.2", "log", "publicsuffix", "serde", "serde_json", "time 0.2.25", - "url 2.2.0", + "url 2.2.1", ] [[package]] @@ -462,6 +515,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "ctr" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "022cd691704491df67d25d006fe8eca083098253c4d43516c2206479c58c6736" +dependencies = [ + "block-cipher-trait", + "stream-cipher", +] + [[package]] name = "ctr" version = "0.6.0" @@ -532,6 +595,16 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" +[[package]] +name = "dns-sd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d748509dea20228f63ba519bf142ce2593396386125b01f5b0d6412dab972087" +dependencies = [ + "libc", + "pkg-config", +] + [[package]] name = "either" version = "1.6.1" @@ -540,9 +613,9 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "env_logger" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26ecb66b4bdca6c1409b40fb255eefc2bd4f6d135dab3c3124f80ffa2a9661e" +checksum = "17392a012ea30ef05a610aa97dfb49496e71c9f676b27879922ea5bdf60d9d3f" dependencies = [ "atty", "humantime", @@ -586,7 +659,7 @@ checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall 0.2.4", + "redox_syscall", "winapi", ] @@ -598,9 +671,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" dependencies = [ "matches", "percent-encoding 2.1.0", @@ -824,9 +897,9 @@ dependencies = [ [[package]] name = "gstreamer" -version = "0.16.5" +version = "0.16.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d50f822055923f1cbede233aa5dfd4ee957cf328fb3076e330886094e11d6cf" +checksum = "9ff5d0f7ff308ae37e6eb47b6ded17785bdea06e438a708cd09e0288c1862f33" dependencies = [ "bitflags", "cfg-if 1.0.0", @@ -974,6 +1047,17 @@ dependencies = [ "digest", ] +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + [[package]] name = "http" version = "0.2.3" @@ -1029,7 +1113,7 @@ dependencies = [ "httparse", "httpdate", "itoa", - "pin-project 1.0.5", + "pin-project", "socket2", "tokio", "tower-service", @@ -1056,15 +1140,36 @@ dependencies = [ [[package]] name = "idna" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de910d521f7cc3135c4de8db1cb910e0b5ed1dc6f57c381cd07e8e661ce10094" +checksum = "89829a5d69c23d348314a7ac337fe39173b61149a9864deabd260983aed48c21" dependencies = [ "matches", "unicode-bidi", "unicode-normalization", ] +[[package]] +name = "if-addrs" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28538916eb3f3976311f5dfbe67b5362d0add1293d0a9cad17debf86f8e3aa48" +dependencies = [ + "if-addrs-sys", + "libc", + "winapi", +] + +[[package]] +name = "if-addrs-sys" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de74b9dd780476e837e5eb5ab7c88b49ed304126e412030a0adba99c8efe79ea" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "indexmap" version = "1.6.1" @@ -1222,6 +1327,24 @@ dependencies = [ "winapi", ] +[[package]] +name = "libmdns" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b276920bfc6c9285e16ffd30ed410487f0185f383483f45a3446afc0554fded" +dependencies = [ + "byteorder", + "futures-util", + "hostname", + "if-addrs", + "log", + "multimap", + "quick-error", + "rand 0.8.3", + "socket2", + "tokio", +] + [[package]] name = "libpulse-binding" version = "2.23.0" @@ -1275,6 +1398,7 @@ name = "librespot" version = "0.1.3" dependencies = [ "librespot-audio", + "librespot-connect", "librespot-core", "librespot-metadata", "librespot-playback", @@ -1285,7 +1409,7 @@ dependencies = [ name = "librespot-audio" version = "0.1.3" dependencies = [ - "aes-ctr", + "aes-ctr 0.6.0", "bit-set", "byteorder", "bytes", @@ -1301,6 +1425,33 @@ dependencies = [ "vorbis", ] +[[package]] +name = "librespot-connect" +version = "0.1.3" +dependencies = [ + "aes-ctr 0.3.0", + "base64 0.13.0", + "block-modes", + "dns-sd", + "futures", + "hmac", + "hyper", + "libmdns", + "librespot-core", + "librespot-playback", + "librespot-protocol", + "log", + "num-bigint", + "protobuf", + "rand 0.7.3", + "serde", + "serde_derive", + "serde_json", + "sha-1", + "tokio", + "url 1.7.2", +] + [[package]] name = "librespot-core" version = "0.1.3" @@ -1434,6 +1585,12 @@ dependencies = [ "libc", ] +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + [[package]] name = "matches" version = "0.1.8" @@ -1458,9 +1615,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e50ae3f04d169fcc9bde0b547d1c205219b7157e07ded9c5aff03e0637cb3ed7" +checksum = "dc250d6848c90d719ea2ce34546fb5df7af1d3fd189d10bf7bad80bfcebecd95" dependencies = [ "libc", "log", @@ -1485,6 +1642,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0419348c027fa7be448d2ae7ea0e4e04c2334c31dc4e74ab29f00a2a7ca69204" +[[package]] +name = "multimap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1255076139a83bb467426e7f8d0134968a8118844faa755985e077cf31850333" +dependencies = [ + "serde", +] + [[package]] name = "ndk" version = "0.2.1" @@ -1726,14 +1892,14 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ccb628cad4f84851442432c60ad8e1f607e29752d0bf072cbd0baf28aa34272" +checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" dependencies = [ "cfg-if 1.0.0", "instant", "libc", - "redox_syscall 0.1.57", + "redox_syscall", "smallvec", "winapi", ] @@ -1786,33 +1952,13 @@ dependencies = [ "ucd-trie", ] -[[package]] -name = "pin-project" -version = "0.4.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffbc8e94b38ea3d2d8ba92aea2983b503cd75d0888d75b86bb37970b5698e15" -dependencies = [ - "pin-project-internal 0.4.27", -] - [[package]] name = "pin-project" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96fa8ebb90271c4477f144354485b8068bd8f6b78b428b01ba892ca26caf0b63" dependencies = [ - "pin-project-internal 1.0.5", -] - -[[package]] -name = "pin-project-internal" -version = "0.4.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65ad2ae56b6abe3a1ee25f15ee605bacadb9a764edaba9c2bf4103800d4a1895" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "pin-project-internal", ] [[package]] @@ -1963,10 +2109,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bbaa49075179162b49acac1c6aa45fb4dafb5f13cf6794276d77bc7fd95757b" dependencies = [ "error-chain", - "idna 0.2.1", + "idna 0.2.2", "lazy_static", "regex", - "url 2.2.0", + "url 2.2.1", ] [[package]] @@ -1978,11 +2124,17 @@ dependencies = [ "percent-encoding 2.1.0", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quote" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ "proc-macro2", ] @@ -2021,7 +2173,7 @@ checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" dependencies = [ "libc", "rand_chacha 0.3.0", - "rand_core 0.6.1", + "rand_core 0.6.2", "rand_hc 0.3.0", ] @@ -2042,7 +2194,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" dependencies = [ "ppv-lite86", - "rand_core 0.6.1", + "rand_core 0.6.2", ] [[package]] @@ -2071,9 +2223,9 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5" +checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" dependencies = [ "getrandom 0.2.2", ] @@ -2093,20 +2245,14 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" dependencies = [ - "rand_core 0.6.1", + "rand_core 0.6.2", ] [[package]] name = "redox_syscall" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" - -[[package]] -name = "redox_syscall" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570" +checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" dependencies = [ "bitflags", ] @@ -2479,6 +2625,15 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" +[[package]] +name = "stream-cipher" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8131256a5896cabcf5eb04f4d6dacbe1aefda854b0d9896e09cb58829ec5638c" +dependencies = [ + "generic-array 0.12.3", +] + [[package]] name = "strsim" version = "0.9.3" @@ -2549,9 +2704,9 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.32" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0313546c01d59e29be4f09687bcb4fb6690cec931cc3607b6aec7a0e417f4cc6" +checksum = "c0bcfbd6a598361fda270d82469fff3d65089dc33e175c9a131f7b4cd395f228" dependencies = [ "filetime", "libc", @@ -2567,7 +2722,7 @@ dependencies = [ "cfg-if 1.0.0", "libc", "rand 0.8.3", - "redox_syscall 0.2.4", + "redox_syscall", "remove_dir_all", "winapi", ] @@ -2583,18 +2738,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76cc616c6abf8c8928e2fdcc0dbfab37175edd8fb49a4641066ad1364fdab146" +checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1" +checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" dependencies = [ "proc-macro2", "quote", @@ -2603,9 +2758,9 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8208a331e1cb318dd5bd76951d2b8fc48ca38a69f5f4e4af1b6a9f8c6236915" +checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd" dependencies = [ "once_cell", ] @@ -2731,9 +2886,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d40a22fd029e33300d8d89a5cc8ffce18bb7c587662f54629e94c9de5487f3" +checksum = "f77d3842f76ca899ff2dbcf231c5c65813dea431301d6eb686279c15c4464f12" dependencies = [ "cfg-if 1.0.0", "pin-project-lite", @@ -2751,11 +2906,11 @@ dependencies = [ [[package]] name = "tracing-futures" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab7bb6f14721aa00656086e9335d363c5c8747bae02ebe32ea2c7dece5689b4c" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" dependencies = [ - "pin-project 0.4.27", + "pin-project", "tracing", ] @@ -2836,7 +2991,7 @@ dependencies = [ "once_cell", "qstring", "rustls", - "url 2.2.0", + "url 2.2.1", "webpki", "webpki-roots", ] @@ -2854,12 +3009,12 @@ dependencies = [ [[package]] name = "url" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5909f2b0817350449ed73e8bcd81c8c3c8d9a7a5d8acba4b27db277f1868976e" +checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b" dependencies = [ "form_urlencoded", - "idna 0.2.1", + "idna 0.2.2", "matches", "percent-encoding 2.1.0", ] diff --git a/Cargo.toml b/Cargo.toml index a7ef8ed4f..fa67c0fcc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,9 +24,9 @@ path = "src/lib.rs" path = "audio" version = "0.1.3" -# [dependencies.librespot-connect] -# path = "connect" -# version = "0.1.3" +[dependencies.librespot-connect] +path = "connect" +version = "0.1.3" [dependencies.librespot-core] path = "core" diff --git a/connect/Cargo.toml b/connect/Cargo.toml index b5cd4fdb1..1f73f01bf 100644 --- a/connect/Cargo.toml +++ b/connect/Cargo.toml @@ -19,8 +19,8 @@ version = "0.1.3" [dependencies] base64 = "0.13" -futures = "0.1" -hyper = "0.12" +futures = "0.3" +hyper = { version = "0.14", features = ["server", "http1"] } log = "0.4" num-bigint = "0.3" protobuf = "~2.14.0" @@ -28,7 +28,7 @@ rand = "0.7" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" -tokio = "0.1" +tokio = { version = "1.0", features = ["macros"] } url = "1.7" sha-1 = "0.8" hmac = "0.7" @@ -36,7 +36,7 @@ aes-ctr = "0.3" block-modes = "0.3" dns-sd = { version = "0.1.3", optional = true } -libmdns = { version = "0.2.7", optional = true } +libmdns = { version = "0.6", optional = true } [features] diff --git a/connect/src/discovery.rs b/connect/src/discovery.rs index f9414ee69..955973593 100644 --- a/connect/src/discovery.rs +++ b/connect/src/discovery.rs @@ -2,15 +2,17 @@ use aes_ctr::stream_cipher::generic_array::GenericArray; use aes_ctr::stream_cipher::{NewStreamCipher, SyncStreamCipher}; use aes_ctr::Aes128Ctr; use base64; -use futures::sync::mpsc; -use futures::{Future, Poll, Stream}; +use futures::channel::mpsc; +use futures::{Stream, StreamExt}; use hmac::{Hmac, Mac}; - -use hyper::{ - self, server::conn::Http, service::Service, Body, Method, Request, Response, StatusCode, -}; +use hyper::service::{make_service_fn, service_fn}; +use hyper::{Body, Method, Request, Response, StatusCode}; use sha1::{Digest, Sha1}; +use std::borrow::Cow; +use std::net::{Ipv4Addr, SocketAddr}; +use std::task::{Context, Poll}; + #[cfg(feature = "with-dns-sd")] use dns_sd::DNSService; @@ -21,8 +23,8 @@ use num_bigint::BigUint; use rand; use std::collections::BTreeMap; use std::io; +use std::pin::Pin; use std::sync::Arc; -use tokio::runtime::current_thread::Handle; use url; use librespot_core::authentication::Credentials; @@ -63,13 +65,8 @@ impl Discovery { (discovery, rx) } -} -impl Discovery { - fn handle_get_info( - &self, - _params: &BTreeMap, - ) -> ::futures::Finished, hyper::Error> { + fn handle_get_info(&self, _: BTreeMap, Cow<'_, str>>) -> Response { let public_key = self.0.public_key.to_bytes_be(); let public_key = base64::encode(&public_key); @@ -93,20 +90,20 @@ impl Discovery { }); let body = result.to_string(); - ::futures::finished(Response::new(Body::from(body))) + Response::new(Body::from(body)) } fn handle_add_user( &self, - params: &BTreeMap, - ) -> ::futures::Finished, hyper::Error> { - let username = params.get("userName").unwrap(); + params: BTreeMap, Cow<'_, str>>, + ) -> Response { + let username = params.get("userName").unwrap().as_ref(); let encrypted_blob = params.get("blob").unwrap(); let client_key = params.get("clientKey").unwrap(); - let encrypted_blob = base64::decode(encrypted_blob).unwrap(); + let encrypted_blob = base64::decode(encrypted_blob.as_bytes()).unwrap(); - let client_key = base64::decode(client_key).unwrap(); + let client_key = base64::decode(client_key.as_bytes()).unwrap(); let client_key = BigUint::from_bytes_be(&client_key); let shared_key = util::powm(&client_key, &self.0.private_key, &DH_PRIME); @@ -141,7 +138,7 @@ impl Discovery { }); let body = result.to_string(); - return ::futures::finished(Response::new(Body::from(body))); + return Response::new(Body::from(body)); } let decrypted = { @@ -155,7 +152,7 @@ impl Discovery { }; let credentials = - Credentials::with_blob(username.to_owned(), &decrypted, &self.0.device_id); + Credentials::with_blob(username.to_string(), &decrypted, &self.0.device_id); self.0.tx.unbounded_send(credentials).unwrap(); @@ -166,52 +163,39 @@ impl Discovery { }); let body = result.to_string(); - return ::futures::finished(Response::new(Body::from(body))); + Response::new(Body::from(body)) } - fn not_found(&self) -> ::futures::Finished, hyper::Error> { + fn not_found(&self) -> Response { let mut res = Response::default(); *res.status_mut() = StatusCode::NOT_FOUND; - ::futures::finished(res) + res } -} -impl Service for Discovery { - type ReqBody = Body; - type ResBody = Body; - type Error = hyper::Error; - - type Future = Box, Error = hyper::Error> + Send>; - fn call(&mut self, request: Request<(Self::ReqBody)>) -> Self::Future { + async fn call(self, request: Request) -> hyper::Result> { let mut params = BTreeMap::new(); let (parts, body) = request.into_parts(); if let Some(query) = parts.uri.query() { - params.extend(url::form_urlencoded::parse(query.as_bytes()).into_owned()); + let query_params = url::form_urlencoded::parse(query.as_bytes()); + params.extend(query_params); } if parts.method != Method::GET { debug!("{:?} {:?} {:?}", parts.method, parts.uri.path(), params); } - let this = self.clone(); - Box::new( - body.fold(Vec::new(), |mut acc, chunk| { - acc.extend_from_slice(chunk.as_ref()); - Ok::<_, hyper::Error>(acc) - }) - .map(move |body| { - params.extend(url::form_urlencoded::parse(&body).into_owned()); - params - }) - .and_then(move |params| { - match (parts.method, params.get("action").map(AsRef::as_ref)) { - (Method::GET, Some("getInfo")) => this.handle_get_info(¶ms), - (Method::POST, Some("addUser")) => this.handle_add_user(¶ms), - _ => this.not_found(), - } - }), + let body = hyper::body::to_bytes(body).await?; + + params.extend(url::form_urlencoded::parse(&body)); + + Ok( + match (parts.method, params.get("action").map(AsRef::as_ref)) { + (Method::GET, Some("getInfo")) => self.handle_get_info(params), + (Method::POST, Some("addUser")) => self.handle_add_user(params), + _ => self.not_found(), + }, ) } } @@ -229,39 +213,25 @@ pub struct DiscoveryStream { } pub fn discovery( - handle: &Handle, config: ConnectConfig, device_id: String, port: u16, ) -> io::Result { let (discovery, creds_rx) = Discovery::new(config.clone(), device_id); - let serve = { - let http = Http::new(); - http.serve_addr(&format!("0.0.0.0:{}", port).parse().unwrap(), move || { - Ok(discovery.clone()) - }) - .unwrap() - }; + let address = SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), port); + + let make_service = make_service_fn(move |_| { + let discovery = discovery.clone(); + async move { Ok::<_, hyper::Error>(service_fn(move |request| discovery.clone().call(request))) } + }); + + let server = hyper::Server::bind(&address).serve(make_service); - let s_port = serve.incoming_ref().local_addr().port(); + let s_port = server.local_addr().port(); debug!("Zeroconf server listening on 0.0.0.0:{}", s_port); - let server_future = { - let handle = handle.clone(); - serve - .for_each( - move |connecting: hyper::server::conn::Connecting< - hyper::server::conn::AddrStream, - futures::Failed<_, hyper::Error>, - >| { - handle.spawn(connecting.flatten().then(|_| Ok(()))).unwrap(); - Ok(()) - }, - ) - .then(|_| Ok(())) - }; - handle.spawn(server_future).unwrap(); + tokio::spawn(server); #[cfg(feature = "with-dns-sd")] let svc = DNSService::register( @@ -275,7 +245,7 @@ pub fn discovery( .unwrap(); #[cfg(not(feature = "with-dns-sd"))] - let responder = libmdns::Responder::spawn(&handle)?; + let responder = libmdns::Responder::spawn(&tokio::runtime::Handle::current())?; #[cfg(not(feature = "with-dns-sd"))] let svc = responder.register( @@ -293,9 +263,8 @@ pub fn discovery( impl Stream for DiscoveryStream { type Item = Credentials; - type Error = (); - fn poll(&mut self) -> Poll, Self::Error> { - self.credentials.poll() + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.credentials.poll_next_unpin(cx) } } diff --git a/connect/src/spirc.rs b/connect/src/spirc.rs index 352a3fcf3..5dc895991 100644 --- a/connect/src/spirc.rs +++ b/connect/src/spirc.rs @@ -1,19 +1,15 @@ -use std; +use std::pin::Pin; use std::time::{SystemTime, UNIX_EPOCH}; -use futures::future; -use futures::sync::mpsc; -use futures::{Async, Future, Poll, Sink, Stream}; -use protobuf::{self, Message}; -use rand; -use rand::seq::SliceRandom; -use serde_json; - use crate::context::StationContext; use crate::playback::mixer::Mixer; use crate::playback::player::{Player, PlayerEvent, PlayerEventChannel}; use crate::protocol; use crate::protocol::spirc::{DeviceState, Frame, MessageType, PlayStatus, State, TrackRef}; +use futures::channel::mpsc; +use futures::future::{self, FusedFuture}; +use futures::stream::FusedStream; +use futures::{Future, FutureExt, Sink, SinkExt, StreamExt}; use librespot_core::config::{ConnectConfig, VolumeCtrl}; use librespot_core::mercury::MercuryError; use librespot_core::session::Session; @@ -21,6 +17,10 @@ use librespot_core::spotify_id::{SpotifyAudioType, SpotifyId, SpotifyIdError}; use librespot_core::util::url_encode; use librespot_core::util::SeqGenerator; use librespot_core::version; +use protobuf::{self, Message}; +use rand; +use rand::seq::SliceRandom; +use serde_json; enum SpircPlayStatus { Stopped, @@ -40,7 +40,11 @@ enum SpircPlayStatus { }, } -pub struct SpircTask { +type BoxedFuture = Pin + Send>>; +type BoxedStream = Pin + Send>>; +type BoxedSink = Pin + Send>>; + +struct SpircTask { player: Player, mixer: Box, config: SpircTaskConfig, @@ -54,15 +58,16 @@ pub struct SpircTask { mixer_started: bool, play_status: SpircPlayStatus, - subscription: Box>, - sender: Box>, + sender_flushed: bool, + subscription: BoxedStream, + sender: BoxedSink, commands: mpsc::UnboundedReceiver, player_events: PlayerEventChannel, shutdown: bool, session: Session, - context_fut: Box>, - autoplay_fut: Box>, + context_fut: BoxedFuture>, + autoplay_fut: BoxedFuture>, context: Option, } @@ -246,7 +251,7 @@ impl Spirc { session: Session, player: Player, mixer: Box, - ) -> (Spirc, SpircTask) { + ) -> (Spirc, impl Future) { debug!("new Spirc[{}]", session.session_id()); let ident = session.device_id().to_owned(); @@ -255,20 +260,23 @@ impl Spirc { debug!("canonical_username: {}", url_encode(&session.username())); let uri = format!("hm://remote/user/{}/", url_encode(&session.username())); - let subscription = session.mercury().subscribe(&uri as &str); - let subscription = subscription - .map(|stream| stream.map_err(|_| MercuryError)) - .flatten_stream(); - let subscription = Box::new(subscription.map(|response| -> Frame { - let data = response.payload.first().unwrap(); - protobuf::parse_from_bytes(data).unwrap() - })); + let subscription = Box::pin( + session + .mercury() + .subscribe(uri.clone()) + .map(Result::unwrap) + .flatten_stream() + .map(|response| -> Frame { + let data = response.payload.first().unwrap(); + protobuf::parse_from_bytes(data).unwrap() + }), + ); - let sender = Box::new( + let sender = Box::pin( session .mercury() .sender(uri) - .with(|frame: Frame| Ok(frame.write_to_bytes().unwrap())), + .with(|frame: Frame| future::ready(Ok(frame.write_to_bytes().unwrap()))), ); let (cmd_tx, cmd_rx) = mpsc::unbounded(); @@ -303,11 +311,12 @@ impl Spirc { commands: cmd_rx, player_events: player_events, + sender_flushed: true, shutdown: false, - session: session.clone(), + session: session, - context_fut: Box::new(future::empty()), - autoplay_fut: Box::new(future::empty()), + context_fut: Box::pin(future::pending()), + autoplay_fut: Box::pin(future::pending()), context: None, }; @@ -317,7 +326,7 @@ impl Spirc { task.hello(); - (spirc, task) + (spirc, task.run()) } pub fn play(&self) { @@ -346,114 +355,80 @@ impl Spirc { } } -impl Future for SpircTask { - type Item = (); - type Error = (); - - fn poll(&mut self) -> Poll<(), ()> { - loop { - let mut progress = false; - - if self.session.is_invalid() { - return Ok(Async::Ready(())); - } - - if !self.shutdown { - match self.subscription.poll().unwrap() { - Async::Ready(Some(frame)) => { - progress = true; - self.handle_frame(frame); - } - Async::Ready(None) => { +impl SpircTask { + async fn run(mut self) { + while !self.session.is_invalid() && !self.shutdown { + tokio::select! { + frame = self.subscription.next() => match frame { + Some(frame) => self.handle_frame(frame), + None => { error!("subscription terminated"); - self.shutdown = true; - self.commands.close(); - } - Async::NotReady => (), - } - - match self.commands.poll().unwrap() { - Async::Ready(Some(command)) => { - progress = true; - self.handle_command(command); - } - Async::Ready(None) => (), - Async::NotReady => (), - } - - match self.player_events.poll() { - Ok(Async::NotReady) => (), - Ok(Async::Ready(None)) => (), - Err(_) => (), - Ok(Async::Ready(Some(event))) => { - progress = true; - self.handle_player_event(event); - } - } - // TODO: Refactor - match self.context_fut.poll() { - Ok(Async::Ready(value)) => { - let r_context = serde_json::from_value::(value.clone()); - self.context = match r_context { - Ok(context) => { - info!( - "Resolved {:?} tracks from <{:?}>", - context.tracks.len(), - self.state.get_context_uri(), - ); - Some(context) - } - Err(e) => { - error!("Unable to parse JSONContext {:?}\n{:?}", e, value); - None - } - }; - // It needn't be so verbose - can be as simple as - // if let Some(ref context) = r_context { - // info!("Got {:?} tracks from <{}>", context.tracks.len(), context.uri); - // } - // self.context = r_context; - - progress = true; - self.context_fut = Box::new(future::empty()); + break; } - Ok(Async::NotReady) => (), - Err(err) => { - self.context_fut = Box::new(future::empty()); - error!("ContextError: {:?}", err) + }, + cmd = self.commands.next(), if !self.commands.is_terminated() => if let Some(cmd) = cmd { + self.handle_command(cmd); + }, + event = self.player_events.next(), if !self.player_events.is_terminated() => if let Some(event) = event { + self.handle_player_event(event) + }, + result = self.sender.flush(), if !self.sender_flushed => { + if result.is_err() { + error!("Cannot flush spirc event sender."); + break; } - } - match self.autoplay_fut.poll() { - Ok(Async::Ready(autoplay_station_uri)) => { - info!("Autoplay uri resolved to <{:?}>", autoplay_station_uri); - self.context_fut = self.resolve_station(&autoplay_station_uri); - progress = true; - self.autoplay_fut = Box::new(future::empty()); + self.sender_flushed = true; + }, + context = &mut self.context_fut, if !self.context_fut.is_terminated() => { + match context { + Ok(value) => { + let r_context = serde_json::from_value::(value); + self.context = match r_context { + Ok(context) => { + info!( + "Resolved {:?} tracks from <{:?}>", + context.tracks.len(), + self.state.get_context_uri(), + ); + Some(context) + } + Err(e) => { + error!("Unable to parse JSONContext {:?}", e); + None + } + }; + // It needn't be so verbose - can be as simple as + // if let Some(ref context) = r_context { + // info!("Got {:?} tracks from <{}>", context.tracks.len(), context.uri); + // } + // self.context = r_context; + }, + Err(err) => { + error!("ContextError: {:?}", err) + } } - Ok(Async::NotReady) => (), - Err(err) => { - self.autoplay_fut = Box::new(future::empty()); - error!("AutoplayError: {:?}", err) + }, + autoplay = &mut self.autoplay_fut, if !self.autoplay_fut.is_terminated() => { + match autoplay { + Ok(autoplay_station_uri) => { + info!("Autoplay uri resolved to <{:?}>", autoplay_station_uri); + self.context_fut = self.resolve_station(&autoplay_station_uri); + }, + Err(err) => { + error!("AutoplayError: {:?}", err) + } } - } - } - - let poll_sender = self.sender.poll_complete().unwrap(); - - // Only shutdown once we've flushed out all our messages - if self.shutdown && poll_sender.is_ready() { - return Ok(Async::Ready(())); + }, + else => break } + } - if !progress { - return Ok(Async::NotReady); - } + if self.sender.close().await.is_err() { + warn!("Cannot close spirc event sender."); } } -} -impl SpircTask { fn now_ms(&mut self) -> i64 { let dur = match SystemTime::now().duration_since(UNIX_EPOCH) { Ok(dur) => dur, @@ -1060,52 +1035,53 @@ impl SpircTask { } } - fn resolve_station( - &self, - uri: &str, - ) -> Box> { + fn resolve_station(&self, uri: &str) -> BoxedFuture> { let radio_uri = format!("hm://radio-apollo/v3/stations/{}", uri); self.resolve_uri(&radio_uri) } - fn resolve_autoplay_uri( - &self, - uri: &str, - ) -> Box> { + fn resolve_autoplay_uri(&self, uri: &str) -> BoxedFuture> { let query_uri = format!("hm://autoplay-enabled/query?uri={}", uri); let request = self.session.mercury().get(query_uri); - Box::new(request.and_then(move |response| { - if response.status_code == 200 { - let data = response - .payload - .first() - .expect("Empty autoplay uri") - .to_vec(); - let autoplay_uri = String::from_utf8(data).unwrap(); - Ok(autoplay_uri) - } else { - warn!("No autoplay_uri found"); - Err(MercuryError) + Box::pin( + async { + let response = request.await?; + + if response.status_code == 200 { + let data = response + .payload + .first() + .expect("Empty autoplay uri") + .to_vec(); + let autoplay_uri = String::from_utf8(data).unwrap(); + Ok(autoplay_uri) + } else { + warn!("No autoplay_uri found"); + Err(MercuryError) + } } - })) + .fuse(), + ) } - fn resolve_uri( - &self, - uri: &str, - ) -> Box> { + fn resolve_uri(&self, uri: &str) -> BoxedFuture> { let request = self.session.mercury().get(uri); - Box::new(request.and_then(move |response| { - let data = response - .payload - .first() - .expect("Empty payload on context uri"); - let response: serde_json::Value = serde_json::from_slice(&data).unwrap(); + Box::pin( + async move { + let response = request.await?; - Ok(response) - })) + let data = response + .payload + .first() + .expect("Empty payload on context uri"); + let response: serde_json::Value = serde_json::from_slice(&data).unwrap(); + + Ok(response) + } + .fuse(), + ) } fn update_tracks_from_context(&mut self) { @@ -1344,8 +1320,14 @@ impl<'a> CommandSender<'a> { if !self.frame.has_state() && self.spirc.device.get_is_active() { self.frame.set_state(self.spirc.state.clone()); } + let sender = &mut self.spirc.sender; + + future::poll_fn(|cx| sender.as_mut().poll_ready(cx)) + .now_or_never() + .unwrap() + .unwrap(); - let send = self.spirc.sender.start_send(self.frame).unwrap(); - assert!(send.is_ready()); + sender.as_mut().start_send(self.frame).unwrap(); + self.spirc.sender_flushed = false; } } diff --git a/core/src/mercury/mod.rs b/core/src/mercury/mod.rs index 72360c972..4baa674f3 100644 --- a/core/src/mercury/mod.rs +++ b/core/src/mercury/mod.rs @@ -102,46 +102,48 @@ impl MercuryManager { MercurySender::new(self.clone(), uri.into()) } - pub async fn subscribe>( + pub fn subscribe>( &self, uri: T, - ) -> Result, MercuryError> { + ) -> impl Future, MercuryError>> + 'static + { let uri = uri.into(); - let response = self - .request(MercuryRequest { - method: MercuryMethod::SUB, - uri: uri.clone(), - content_type: None, - payload: Vec::new(), - }) - .await?; - - let (tx, rx) = mpsc::unbounded(); + let request = self.request(MercuryRequest { + method: MercuryMethod::SUB, + uri: uri.clone(), + content_type: None, + payload: Vec::new(), + }); let manager = self.clone(); + async move { + let response = request.await?; - manager.lock(move |inner| { - if !inner.invalid { - debug!("subscribed uri={} count={}", uri, response.payload.len()); - if !response.payload.is_empty() { - // Old subscription protocol, watch the provided list of URIs - for sub in response.payload { - let mut sub: protocol::pubsub::Subscription = - protobuf::parse_from_bytes(&sub).unwrap(); - let sub_uri = sub.take_uri(); + let (tx, rx) = mpsc::unbounded(); - debug!("subscribed sub_uri={}", sub_uri); + manager.lock(move |inner| { + if !inner.invalid { + debug!("subscribed uri={} count={}", uri, response.payload.len()); + if !response.payload.is_empty() { + // Old subscription protocol, watch the provided list of URIs + for sub in response.payload { + let mut sub: protocol::pubsub::Subscription = + protobuf::parse_from_bytes(&sub).unwrap(); + let sub_uri = sub.take_uri(); - inner.subscriptions.push((sub_uri, tx.clone())); + debug!("subscribed sub_uri={}", sub_uri); + + inner.subscriptions.push((sub_uri, tx.clone())); + } + } else { + // New subscription protocol, watch the requested URI + inner.subscriptions.push((uri, tx)); } - } else { - // New subscription protocol, watch the requested URI - inner.subscriptions.push((uri, tx)); } - } - }); + }); - Ok(rx) + Ok(rx) + } } pub(crate) fn dispatch(&self, cmd: u8, mut data: Bytes) { diff --git a/src/lib.rs b/src/lib.rs index 4304e187a..7cdd31789 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ #![crate_name = "librespot"] pub extern crate librespot_audio as audio; -// pub extern crate librespot_connect as connect; +pub extern crate librespot_connect as connect; pub extern crate librespot_core as core; pub extern crate librespot_metadata as metadata; pub extern crate librespot_playback as playback; From 2c81aaaf4e440a41ca5c2a37f0f760e70958951b Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Sat, 20 Feb 2021 20:59:57 +0100 Subject: [PATCH 31/75] Implement MercurySender not as sink --- connect/src/spirc.rs | 39 +++++++-------------------- core/src/mercury/sender.rs | 55 ++++++++++++-------------------------- 2 files changed, 27 insertions(+), 67 deletions(-) diff --git a/connect/src/spirc.rs b/connect/src/spirc.rs index 5dc895991..2e3694e4f 100644 --- a/connect/src/spirc.rs +++ b/connect/src/spirc.rs @@ -9,9 +9,9 @@ use crate::protocol::spirc::{DeviceState, Frame, MessageType, PlayStatus, State, use futures::channel::mpsc; use futures::future::{self, FusedFuture}; use futures::stream::FusedStream; -use futures::{Future, FutureExt, Sink, SinkExt, StreamExt}; +use futures::{Future, FutureExt, StreamExt}; use librespot_core::config::{ConnectConfig, VolumeCtrl}; -use librespot_core::mercury::MercuryError; +use librespot_core::mercury::{MercuryError, MercurySender}; use librespot_core::session::Session; use librespot_core::spotify_id::{SpotifyAudioType, SpotifyId, SpotifyIdError}; use librespot_core::util::url_encode; @@ -42,7 +42,6 @@ enum SpircPlayStatus { type BoxedFuture = Pin + Send>>; type BoxedStream = Pin + Send>>; -type BoxedSink = Pin + Send>>; struct SpircTask { player: Player, @@ -58,9 +57,8 @@ struct SpircTask { mixer_started: bool, play_status: SpircPlayStatus, - sender_flushed: bool, subscription: BoxedStream, - sender: BoxedSink, + sender: MercurySender, commands: mpsc::UnboundedReceiver, player_events: PlayerEventChannel, @@ -272,12 +270,7 @@ impl Spirc { }), ); - let sender = Box::pin( - session - .mercury() - .sender(uri) - .with(|frame: Frame| future::ready(Ok(frame.write_to_bytes().unwrap()))), - ); + let sender = session.mercury().sender(uri); let (cmd_tx, cmd_rx) = mpsc::unbounded(); @@ -311,7 +304,6 @@ impl Spirc { commands: cmd_rx, player_events: player_events, - sender_flushed: true, shutdown: false, session: session, @@ -372,13 +364,9 @@ impl SpircTask { event = self.player_events.next(), if !self.player_events.is_terminated() => if let Some(event) = event { self.handle_player_event(event) }, - result = self.sender.flush(), if !self.sender_flushed => { - if result.is_err() { - error!("Cannot flush spirc event sender."); - break; - } - - self.sender_flushed = true; + result = self.sender.flush(), if !self.sender.is_flushed() => if result.is_err() { + error!("Cannot flush spirc event sender."); + break; }, context = &mut self.context_fut, if !self.context_fut.is_terminated() => { match context { @@ -424,8 +412,8 @@ impl SpircTask { } } - if self.sender.close().await.is_err() { - warn!("Cannot close spirc event sender."); + if self.sender.flush().await.is_err() { + warn!("Cannot flush spirc event sender."); } } @@ -1320,14 +1308,7 @@ impl<'a> CommandSender<'a> { if !self.frame.has_state() && self.spirc.device.get_is_active() { self.frame.set_state(self.spirc.state.clone()); } - let sender = &mut self.spirc.sender; - - future::poll_fn(|cx| sender.as_mut().poll_ready(cx)) - .now_or_never() - .unwrap() - .unwrap(); - sender.as_mut().start_send(self.frame).unwrap(); - self.spirc.sender_flushed = false; + self.spirc.sender.send(self.frame.write_to_bytes().unwrap()); } } diff --git a/core/src/mercury/sender.rs b/core/src/mercury/sender.rs index 860c2f335..e276bcf1e 100644 --- a/core/src/mercury/sender.rs +++ b/core/src/mercury/sender.rs @@ -1,5 +1,4 @@ -use futures::Sink; -use std::{collections::VecDeque, pin::Pin, task::Context}; +use std::collections::VecDeque; use super::*; @@ -18,6 +17,22 @@ impl MercurySender { pending: VecDeque::new(), } } + + pub fn is_flushed(&self) -> bool { + self.pending.is_empty() + } + + pub fn send(&mut self, item: Vec) { + let task = self.mercury.send(self.uri.clone(), item); + self.pending.push_back(task); + } + + pub async fn flush(&mut self) -> Result<(), MercuryError> { + for fut in self.pending.drain(..) { + fut.await?; + } + Ok(()) + } } impl Clone for MercurySender { @@ -29,39 +44,3 @@ impl Clone for MercurySender { } } } - -impl Sink> for MercurySender { - type Error = MercuryError; - - fn poll_ready(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } - - fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.poll_flush(cx) - } - - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - loop { - match self.pending.front_mut() { - Some(task) => { - match Pin::new(task).poll(cx) { - Poll::Ready(Err(x)) => return Poll::Ready(Err(x)), - Poll::Pending => return Poll::Pending, - _ => (), - }; - } - None => { - return Poll::Ready(Ok(())); - } - } - self.pending.pop_front(); - } - } - - fn start_send(mut self: Pin<&mut Self>, item: Vec) -> Result<(), Self::Error> { - let task = self.mercury.send(self.uri.clone(), item); - self.pending.push_back(task); - Ok(()) - } -} From 1c4d57c6da9631397021b822ef24624374648c68 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Sat, 20 Feb 2021 21:26:52 +0100 Subject: [PATCH 32/75] Add shutdown to discovery server --- connect/src/discovery.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/connect/src/discovery.rs b/connect/src/discovery.rs index 955973593..62310b2ff 100644 --- a/connect/src/discovery.rs +++ b/connect/src/discovery.rs @@ -2,7 +2,7 @@ use aes_ctr::stream_cipher::generic_array::GenericArray; use aes_ctr::stream_cipher::{NewStreamCipher, SyncStreamCipher}; use aes_ctr::Aes128Ctr; use base64; -use futures::channel::mpsc; +use futures::channel::{mpsc, oneshot}; use futures::{Stream, StreamExt}; use hmac::{Hmac, Mac}; use hyper::service::{make_service_fn, service_fn}; @@ -10,6 +10,7 @@ use hyper::{Body, Method, Request, Response, StatusCode}; use sha1::{Digest, Sha1}; use std::borrow::Cow; +use std::convert::Infallible; use std::net::{Ipv4Addr, SocketAddr}; use std::task::{Context, Poll}; @@ -204,12 +205,14 @@ impl Discovery { pub struct DiscoveryStream { credentials: mpsc::UnboundedReceiver, _svc: DNSService, + _close_tx: oneshot::Sender, } #[cfg(not(feature = "with-dns-sd"))] pub struct DiscoveryStream { credentials: mpsc::UnboundedReceiver, _svc: libmdns::Service, + _close_tx: oneshot::Sender, } pub fn discovery( @@ -218,6 +221,7 @@ pub fn discovery( port: u16, ) -> io::Result { let (discovery, creds_rx) = Discovery::new(config.clone(), device_id); + let (close_tx, close_rx) = oneshot::channel(); let address = SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), port); @@ -231,7 +235,10 @@ pub fn discovery( let s_port = server.local_addr().port(); debug!("Zeroconf server listening on 0.0.0.0:{}", s_port); - tokio::spawn(server); + tokio::spawn(server.with_graceful_shutdown(async { + close_rx.await.unwrap_err(); + debug!("Shutting down discovery server"); + })); #[cfg(feature = "with-dns-sd")] let svc = DNSService::register( @@ -258,6 +265,7 @@ pub fn discovery( Ok(DiscoveryStream { credentials: creds_rx, _svc: svc, + _close_tx: close_tx, }) } From 007e653f3d2f3f84ab6c88c847ee84d2a35d7df1 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Sat, 20 Feb 2021 22:14:15 +0100 Subject: [PATCH 33/75] Restore original blocking player behaviour --- core/src/session.rs | 15 ++++- playback/src/player.rs | 134 ++++++++++++++++++++--------------------- 2 files changed, 80 insertions(+), 69 deletions(-) diff --git a/core/src/session.rs b/core/src/session.rs index fd7067981..b0eca0c00 100644 --- a/core/src/session.rs +++ b/core/src/session.rs @@ -39,6 +39,8 @@ struct SessionInternal { mercury: OnceCell, cache: Option>, + handle: tokio::runtime::Handle, + session_id: usize, } @@ -65,7 +67,13 @@ impl Session { cache.save_credentials(&reusable_credentials); } - let session = Session::create(conn, config, cache, reusable_credentials.username); + let session = Session::create( + conn, + config, + cache, + reusable_credentials.username, + tokio::runtime::Handle::current(), + ); Ok(session) } @@ -75,6 +83,7 @@ impl Session { config: SessionConfig, cache: Option, username: String, + handle: tokio::runtime::Handle, ) -> Session { let (sink, stream) = transport.split(); @@ -100,6 +109,8 @@ impl Session { channel: OnceCell::new(), mercury: OnceCell::new(), + handle, + session_id: session_id, })); @@ -139,7 +150,7 @@ impl Session { T: Future + Send + 'static, T::Output: Send + 'static, { - tokio::spawn(task); + self.0.handle.spawn(task); } fn debug_info(&self) { diff --git a/playback/src/player.rs b/playback/src/player.rs index 6f6a85aef..3ee5c9896 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -7,7 +7,6 @@ use crate::audio::{ use crate::audio_backend::Sink; use crate::config::NormalisationType; use crate::config::{Bitrate, PlayerConfig}; -use crate::librespot_core::tokio; use crate::metadata::{AudioItem, FileFormat}; use crate::mixer::AudioFilter; use librespot_core::session::Session; @@ -15,25 +14,22 @@ use librespot_core::spotify_id::SpotifyId; use librespot_core::util::SeqGenerator; use byteorder::{LittleEndian, ReadBytesExt}; -use futures::{ - channel::{mpsc, oneshot}, - future, Future, Stream, StreamExt, -}; -use std::io::{Read, Seek, SeekFrom}; -use std::mem; +use futures::channel::{mpsc, oneshot}; +use futures::{future, Future, Stream, StreamExt, TryFutureExt}; +use std::borrow::Cow; + +use std::cmp::max; +use std::io::{self, Read, Seek, SeekFrom}; +use std::pin::Pin; +use std::task::{Context, Poll}; use std::time::{Duration, Instant}; -use std::{borrow::Cow, io}; -use std::{ - cmp::max, - pin::Pin, - task::{Context, Poll}, -}; +use std::{mem, thread}; const PRELOAD_NEXT_TRACK_BEFORE_END_DURATION_MS: u32 = 30000; pub struct Player { commands: Option>, - task_handle: Option>, + thread_handle: Option>, play_request_id_generator: SeqGenerator, } @@ -251,33 +247,33 @@ impl Player { let (cmd_tx, cmd_rx) = mpsc::unbounded(); let (event_sender, event_receiver) = mpsc::unbounded(); - debug!("new Player[{}]", session.session_id()); - - let internal = PlayerInternal { - session: session, - config: config, - commands: cmd_rx, - - state: PlayerState::Stopped, - preload: PlayerPreload::None, - sink: sink_builder(), - sink_status: SinkStatus::Closed, - sink_event_callback: None, - audio_filter: audio_filter, - event_senders: [event_sender].to_vec(), - }; + let handle = thread::spawn(move || { + debug!("new Player[{}]", session.session_id()); + + let internal = PlayerInternal { + session: session, + config: config, + commands: cmd_rx, + + state: PlayerState::Stopped, + preload: PlayerPreload::None, + sink: sink_builder(), + sink_status: SinkStatus::Closed, + sink_event_callback: None, + audio_filter: audio_filter, + event_senders: [event_sender].to_vec(), + }; - // While PlayerInternal is written as a future, it still contains blocking code. - // It must be run by using wait() in a dedicated thread. - let handle = tokio::spawn(async move { - internal.await; + // While PlayerInternal is written as a future, it still contains blocking code. + // It must be run by using wait() in a dedicated thread. + futures::executor::block_on(internal); debug!("PlayerInternal thread finished."); }); ( Player { commands: Some(cmd_tx), - task_handle: Some(handle), + thread_handle: Some(handle), play_request_id_generator: SeqGenerator::new(0), }, event_receiver, @@ -351,13 +347,11 @@ impl Drop for Player { fn drop(&mut self) { debug!("Shutting down player thread ..."); self.commands = None; - if let Some(handle) = self.task_handle.take() { - tokio::spawn(async { - match handle.await { - Ok(_) => (), - Err(_) => error!("Player thread panicked!"), - } - }); + if let Some(handle) = self.thread_handle.take() { + match handle.join() { + Ok(_) => (), + Err(_) => error!("Player thread panicked!"), + } } } } @@ -436,15 +430,23 @@ impl PlayerState { #[allow(dead_code)] fn is_stopped(&self) -> bool { - matches!(self, Self::Stopped) + use self::PlayerState::*; + match *self { + Stopped => true, + _ => false, + } } fn is_loading(&self) -> bool { - matches!(self, Self::Loading { .. }) + use self::PlayerState::*; + match *self { + Loading { .. } => true, + _ => false, + } } fn decoder(&mut self) -> Option<&mut Decoder> { - use PlayerState::*; + use self::PlayerState::*; match *self { Stopped | EndOfTrack { .. } | Loading { .. } => None, Paused { @@ -1243,9 +1245,10 @@ impl PlayerInternal { loaded_track .stream_loader_controller .set_random_access_mode(); - let _ = tokio::task::block_in_place(|| { - loaded_track.decoder.seek(position_ms as i64) - }); + let _ = loaded_track.decoder.seek(position_ms as i64); // This may be blocking. + // But most likely the track is fully + // loaded already because we played + // to the end of it. loaded_track.stream_loader_controller.set_stream_mode(); loaded_track.stream_position_pcm = Self::position_ms_to_pcm(position_ms); } @@ -1278,7 +1281,7 @@ impl PlayerInternal { // we can use the current decoder. Ensure it's at the correct position. if Self::position_ms_to_pcm(position_ms) != *stream_position_pcm { stream_loader_controller.set_random_access_mode(); - let _ = tokio::task::block_in_place(|| decoder.seek(position_ms as i64)); + let _ = decoder.seek(position_ms as i64); // This may be blocking. stream_loader_controller.set_stream_mode(); *stream_position_pcm = Self::position_ms_to_pcm(position_ms); } @@ -1346,9 +1349,7 @@ impl PlayerInternal { loaded_track .stream_loader_controller .set_random_access_mode(); - let _ = tokio::task::block_in_place(|| { - loaded_track.decoder.seek(position_ms as i64) - }); + let _ = loaded_track.decoder.seek(position_ms as i64); // This may be blocking loaded_track.stream_loader_controller.set_stream_mode(); } self.start_playback(track_id, play_request_id, *loaded_track, play); @@ -1563,7 +1564,7 @@ impl PlayerInternal { } } - pub fn load_track( + fn load_track( &self, spotify_id: SpotifyId, position_ms: u32, @@ -1574,22 +1575,23 @@ impl PlayerInternal { // easily. Instead we spawn a thread to do the work and return a one-shot channel as the // future to work with. - let session = self.session.clone(); - let config = self.config.clone(); - - async move { - let loader = PlayerTrackLoader { session, config }; + let loader = PlayerTrackLoader { + session: self.session.clone(), + config: self.config.clone(), + }; - let (result_tx, result_rx) = oneshot::channel(); + let (result_tx, result_rx) = oneshot::channel(); - tokio::spawn(async move { - if let Some(data) = loader.load_track(spotify_id, position_ms).await { + std::thread::spawn(move || { + futures::executor::block_on(loader.load_track(spotify_id, position_ms)).and_then( + move |data| { let _ = result_tx.send(data); - } - }); + Some(()) + }, + ); + }); - result_rx.await.map_err(|_| ()) - } + result_rx.map_err(|_| ()) } fn preload_data_before_playback(&mut self) { @@ -1615,9 +1617,7 @@ impl PlayerInternal { * bytes_per_second as f64) as usize, (READ_AHEAD_BEFORE_PLAYBACK_SECONDS * bytes_per_second as f64) as usize, ); - tokio::task::block_in_place(|| { - stream_loader_controller.fetch_next_blocking(wait_for_data_length) - }); + stream_loader_controller.fetch_next_blocking(wait_for_data_length); } } } From 220061e1581dd1c6889f8d302b3f747f5a68c8d4 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Sun, 21 Feb 2021 11:08:34 +0100 Subject: [PATCH 34/75] Migrate application to tokio 1.0 --- Cargo.lock | 57 ++++ Cargo.toml | 24 +- src/main.rs | 600 ++++++++++++++++++++++++++++++++++++ src/player_event_handler.rs | 36 ++- 4 files changed, 697 insertions(+), 20 deletions(-) create mode 100644 src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 6b6e7af24..50234e980 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -805,6 +805,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +dependencies = [ + "unicode-width", +] + [[package]] name = "getrandom" version = "0.1.16" @@ -1037,6 +1046,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hex" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" + [[package]] name = "hmac" version = "0.7.1" @@ -1397,12 +1412,26 @@ dependencies = [ name = "librespot" version = "0.1.3" dependencies = [ + "base64 0.13.0", + "env_logger", + "futures", + "getopts", + "hex", + "hyper", "librespot-audio", "librespot-connect", "librespot-core", "librespot-metadata", "librespot-playback", "librespot-protocol", + "log", + "num-bigint", + "protobuf", + "rand 0.7.3", + "rpassword", + "sha-1", + "tokio", + "url 1.7.2", ] [[package]] @@ -2314,6 +2343,16 @@ dependencies = [ "cpal", ] +[[package]] +name = "rpassword" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc936cf8a7ea60c58f030fd36a612a48f440610214dc54bc36431f9ea0c3efb" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "rustc-demangle" version = "0.1.18" @@ -2532,6 +2571,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" +[[package]] +name = "signal-hook-registry" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6" +dependencies = [ + "libc", +] + [[package]] name = "slab" version = "0.4.2" @@ -2840,8 +2888,11 @@ dependencies = [ "memchr", "mio", "num_cpus", + "once_cell", "pin-project-lite", + "signal-hook-registry", "tokio-macros", + "winapi", ] [[package]] @@ -2956,6 +3007,12 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" +[[package]] +name = "unicode-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" + [[package]] name = "unicode-xid" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index fa67c0fcc..e4f9c51ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,10 +15,10 @@ edition = "2018" name = "librespot" path = "src/lib.rs" -# [[bin]] -# name = "librespot" -# path = "src/main.rs" -# doc = false +[[bin]] +name = "librespot" +path = "src/main.rs" +doc = false [dependencies.librespot-audio] path = "audio" @@ -44,6 +44,22 @@ version = "0.1.3" path = "protocol" version = "0.1.3" +[dependencies] +base64 = "0.13" +env_logger = {version = "0.8", default-features = false, features = ["termcolor","humantime","atty"]} +futures = "0.3" +getopts = "0.2" +hyper = "0.14" +log = "0.4" +num-bigint = "0.3" +protobuf = "~2.14.0" +rand = "0.7" +rpassword = "5.0" +tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros", "signal", "process"] } +url = "1.7" +sha-1 = "0.8" +hex = "0.4" + [features] alsa-backend = ["librespot-playback/alsa-backend"] portaudio-backend = ["librespot-playback/portaudio-backend"] diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 000000000..1392c2017 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,600 @@ +use futures::{channel::mpsc::UnboundedReceiver, future::FusedFuture, FutureExt, StreamExt}; +use librespot_playback::player::PlayerEvent; +use log::{error, info, warn}; +use sha1::{Digest, Sha1}; +use std::path::Path; +use std::process::exit; +use std::str::FromStr; +use std::{env, time::Instant}; +use std::{ + io::{stderr, Write}, + pin::Pin, +}; +use url::Url; + +use librespot::core::authentication::{get_credentials, Credentials}; +use librespot::core::cache::Cache; +use librespot::core::config::{ConnectConfig, DeviceType, SessionConfig, VolumeCtrl}; +use librespot::core::session::Session; +use librespot::core::version; + +use librespot::connect::spirc::Spirc; +use librespot::playback::audio_backend::{self, Sink, BACKENDS}; +use librespot::playback::config::{Bitrate, NormalisationType, PlayerConfig}; +use librespot::playback::mixer::{self, Mixer, MixerConfig}; +use librespot::playback::player::Player; + +mod player_event_handler; + +use player_event_handler::{emit_sink_event, run_program_on_events}; + +fn device_id(name: &str) -> String { + hex::encode(Sha1::digest(name.as_bytes())) +} + +fn usage(program: &str, opts: &getopts::Options) -> String { + let brief = format!("Usage: {} [options]", program); + opts.usage(&brief) +} + +fn setup_logging(verbose: bool) { + let mut builder = env_logger::Builder::new(); + match env::var("RUST_LOG") { + Ok(config) => { + builder.parse_filters(&config); + builder.init(); + + if verbose { + warn!("`--verbose` flag overidden by `RUST_LOG` environment variable"); + } + } + Err(_) => { + if verbose { + builder.parse_filters("libmdns=info,librespot=trace"); + } else { + builder.parse_filters("libmdns=info,librespot=info"); + } + builder.init(); + } + } +} + +fn list_backends() { + println!("Available Backends : "); + for (&(name, _), idx) in BACKENDS.iter().zip(0..) { + if idx == 0 { + println!("- {} (default)", name); + } else { + println!("- {}", name); + } + } +} + +#[derive(Clone)] +struct Setup { + backend: fn(Option) -> Box, + device: Option, + + mixer: fn(Option) -> Box, + + cache: Option, + player_config: PlayerConfig, + session_config: SessionConfig, + connect_config: ConnectConfig, + mixer_config: MixerConfig, + credentials: Option, + enable_discovery: bool, + zeroconf_port: u16, + player_event_program: Option, + emit_sink_events: bool, +} + +fn setup(args: &[String]) -> Setup { + let mut opts = getopts::Options::new(); + opts.optopt( + "c", + "cache", + "Path to a directory where files will be cached.", + "CACHE", + ).optopt( + "", + "system-cache", + "Path to a directory where system files (credentials, volume) will be cached. Can be different from cache option value", + "SYTEMCACHE", + ).optflag("", "disable-audio-cache", "Disable caching of the audio data.") + .reqopt("n", "name", "Device name", "NAME") + .optopt("", "device-type", "Displayed device type", "DEVICE_TYPE") + .optopt( + "b", + "bitrate", + "Bitrate (96, 160 or 320). Defaults to 160", + "BITRATE", + ) + .optopt( + "", + "onevent", + "Run PROGRAM when playback is about to begin.", + "PROGRAM", + ) + .optflag("", "emit-sink-events", "Run program set by --onevent before sink is opened and after it is closed.") + .optflag("v", "verbose", "Enable verbose output") + .optopt("u", "username", "Username to sign in with", "USERNAME") + .optopt("p", "password", "Password", "PASSWORD") + .optopt("", "proxy", "HTTP proxy to use when connecting", "PROXY") + .optopt("", "ap-port", "Connect to AP with specified port. If no AP with that port are present fallback AP will be used. Available ports are usually 80, 443 and 4070", "AP_PORT") + .optflag("", "disable-discovery", "Disable discovery mode") + .optopt( + "", + "backend", + "Audio backend to use. Use '?' to list options", + "BACKEND", + ) + .optopt( + "", + "device", + "Audio device to use. Use '?' to list options if using portaudio or alsa", + "DEVICE", + ) + .optopt("", "mixer", "Mixer to use (alsa or softvol)", "MIXER") + .optopt( + "m", + "mixer-name", + "Alsa mixer name, e.g \"PCM\" or \"Master\". Defaults to 'PCM'", + "MIXER_NAME", + ) + .optopt( + "", + "mixer-card", + "Alsa mixer card, e.g \"hw:0\" or similar from `aplay -l`. Defaults to 'default' ", + "MIXER_CARD", + ) + .optopt( + "", + "mixer-index", + "Alsa mixer index, Index of the cards mixer. Defaults to 0", + "MIXER_INDEX", + ) + .optflag( + "", + "mixer-linear-volume", + "Disable alsa's mapped volume scale (cubic). Default false", + ) + .optopt( + "", + "initial-volume", + "Initial volume in %, once connected (must be from 0 to 100)", + "VOLUME", + ) + .optopt( + "", + "zeroconf-port", + "The port the internal server advertised over zeroconf uses.", + "ZEROCONF_PORT", + ) + .optflag( + "", + "enable-volume-normalisation", + "Play all tracks at the same volume", + ) + .optopt( + "", + "normalisation-gain-type", + "Specify the normalisation gain type to use - [track, album]. Default is album.", + "GAIN_TYPE", + ) + .optopt( + "", + "normalisation-pregain", + "Pregain (dB) applied by volume normalisation", + "PREGAIN", + ) + .optopt( + "", + "volume-ctrl", + "Volume control type - [linear, log, fixed]. Default is logarithmic", + "VOLUME_CTRL" + ) + .optflag( + "", + "autoplay", + "autoplay similar songs when your music ends.", + ) + .optflag( + "", + "disable-gapless", + "disable gapless playback.", + ); + + let matches = match opts.parse(&args[1..]) { + Ok(m) => m, + Err(f) => { + writeln!( + stderr(), + "error: {}\n{}", + f.to_string(), + usage(&args[0], &opts) + ) + .unwrap(); + exit(1); + } + }; + + let verbose = matches.opt_present("verbose"); + setup_logging(verbose); + + info!( + "librespot {} ({}). Built on {}. Build ID: {}", + version::short_sha(), + version::commit_date(), + version::short_now(), + version::build_id() + ); + + let backend_name = matches.opt_str("backend"); + if backend_name == Some("?".into()) { + list_backends(); + exit(0); + } + + let backend = audio_backend::find(backend_name).expect("Invalid backend"); + + let device = matches.opt_str("device"); + if device == Some("?".into()) { + backend(device); + exit(0); + } + + let mixer_name = matches.opt_str("mixer"); + let mixer = mixer::find(mixer_name.as_ref()).expect("Invalid mixer"); + + let mixer_config = MixerConfig { + card: matches + .opt_str("mixer-card") + .unwrap_or_else(|| String::from("default")), + mixer: matches + .opt_str("mixer-name") + .unwrap_or_else(|| String::from("PCM")), + index: matches + .opt_str("mixer-index") + .map(|index| index.parse::().unwrap()) + .unwrap_or(0), + mapped_volume: !matches.opt_present("mixer-linear-volume"), + }; + + let cache = { + let audio_dir; + let system_dir; + if matches.opt_present("disable-audio-cache") { + audio_dir = None; + system_dir = matches + .opt_str("system-cache") + .or_else(|| matches.opt_str("c")) + .map(|p| p.into()); + } else { + let cache_dir = matches.opt_str("c"); + audio_dir = cache_dir + .as_ref() + .map(|p| AsRef::::as_ref(p).join("files")); + system_dir = matches + .opt_str("system-cache") + .or(cache_dir) + .map(|p| p.into()); + } + + match Cache::new(system_dir, audio_dir) { + Ok(cache) => Some(cache), + Err(e) => { + warn!("Cannot create cache: {}", e); + None + } + } + }; + + let initial_volume = matches + .opt_str("initial-volume") + .map(|volume| { + let volume = volume.parse::().unwrap(); + if volume > 100 { + panic!("Initial volume must be in the range 0-100"); + } + (volume as i32 * 0xFFFF / 100) as u16 + }) + .or_else(|| cache.as_ref().and_then(Cache::volume)) + .unwrap_or(0x8000); + + let zeroconf_port = matches + .opt_str("zeroconf-port") + .map(|port| port.parse::().unwrap()) + .unwrap_or(0); + + let name = matches.opt_str("name").unwrap(); + + let credentials = { + let cached_credentials = cache.as_ref().and_then(Cache::credentials); + + let password = |username: &String| -> String { + write!(stderr(), "Password for {}: ", username).unwrap(); + stderr().flush().unwrap(); + rpassword::read_password().unwrap() + }; + + get_credentials( + matches.opt_str("username"), + matches.opt_str("password"), + cached_credentials, + password, + ) + }; + + let session_config = { + let device_id = device_id(&name); + + SessionConfig { + user_agent: version::version_string(), + device_id: device_id, + proxy: matches.opt_str("proxy").or(std::env::var("http_proxy").ok()).map( + |s| { + match Url::parse(&s) { + Ok(url) => { + if url.host().is_none() || url.port_or_known_default().is_none() { + panic!("Invalid proxy url, only urls on the format \"http://host:port\" are allowed"); + } + + if url.scheme() != "http" { + panic!("Only unsecure http:// proxies are supported"); + } + url + }, + Err(err) => panic!("Invalid proxy url: {}, only urls on the format \"http://host:port\" are allowed", err) + } + }, + ), + ap_port: matches + .opt_str("ap-port") + .map(|port| port.parse::().expect("Invalid port")), + } + }; + + let player_config = { + let bitrate = matches + .opt_str("b") + .as_ref() + .map(|bitrate| Bitrate::from_str(bitrate).expect("Invalid bitrate")) + .unwrap_or(Bitrate::default()); + let gain_type = matches + .opt_str("normalisation-gain-type") + .as_ref() + .map(|gain_type| { + NormalisationType::from_str(gain_type).expect("Invalid normalisation type") + }) + .unwrap_or(NormalisationType::default()); + PlayerConfig { + bitrate: bitrate, + gapless: !matches.opt_present("disable-gapless"), + normalisation: matches.opt_present("enable-volume-normalisation"), + normalisation_type: gain_type, + normalisation_pregain: matches + .opt_str("normalisation-pregain") + .map(|pregain| pregain.parse::().expect("Invalid pregain float value")) + .unwrap_or(PlayerConfig::default().normalisation_pregain), + } + }; + + let connect_config = { + let device_type = matches + .opt_str("device-type") + .as_ref() + .map(|device_type| DeviceType::from_str(device_type).expect("Invalid device type")) + .unwrap_or(DeviceType::default()); + + let volume_ctrl = matches + .opt_str("volume-ctrl") + .as_ref() + .map(|volume_ctrl| VolumeCtrl::from_str(volume_ctrl).expect("Invalid volume ctrl type")) + .unwrap_or(VolumeCtrl::default()); + + ConnectConfig { + name: name, + device_type: device_type, + volume: initial_volume, + volume_ctrl: volume_ctrl, + autoplay: matches.opt_present("autoplay"), + } + }; + + let enable_discovery = !matches.opt_present("disable-discovery"); + + Setup { + backend: backend, + cache: cache, + session_config: session_config, + player_config: player_config, + connect_config: connect_config, + credentials: credentials, + device: device, + enable_discovery: enable_discovery, + zeroconf_port: zeroconf_port, + mixer: mixer, + mixer_config: mixer_config, + player_event_program: matches.opt_str("onevent"), + emit_sink_events: matches.opt_present("emit-sink-events"), + } +} + +#[tokio::main] +async fn main() { + if env::var("RUST_BACKTRACE").is_err() { + env::set_var("RUST_BACKTRACE", "full") + } + + let args: Vec = std::env::args().collect(); + let setupp = setup(&args); + + let mut last_credentials = None; + let mut spirc: Option = None; + let mut spirc_task: Option> = None; + let mut player_event_channel: Option> = None; + let mut auto_connect_times: Vec = vec![]; + let mut discovery = None; + let mut connecting: Pin>> = + Box::pin(futures::future::pending()); + + if setupp.enable_discovery { + let config = setupp.connect_config.clone(); + let device_id = setupp.session_config.device_id.clone(); + + discovery = Some( + librespot_connect::discovery::discovery(config, device_id, setupp.zeroconf_port) + .unwrap(), + ); + } + + if let Some(credentials) = setupp.credentials { + last_credentials = Some(credentials.clone()); + connecting = Box::pin( + Session::connect( + setupp.session_config.clone(), + credentials, + setupp.cache.clone(), + ) + .fuse(), + ); + } + + loop { + tokio::select! { + credentials = async { discovery.as_mut().unwrap().next().await }, if discovery.is_some() => { + match credentials { + Some(credentials) => { + last_credentials = Some(credentials.clone()); + auto_connect_times.clear(); + + if let Some(spirc) = spirc.take() { + spirc.shutdown(); + } + if let Some(spirc_task) = spirc_task.take() { + // Continue shutdown in its own task + tokio::spawn(spirc_task); + } + + connecting = Box::pin(Session::connect( + setupp.session_config.clone(), + credentials, + setupp.cache.clone(), + ).fuse()); + }, + None => { + warn!("Discovery stopped!"); + discovery = None; + } + } + }, + session = &mut connecting, if !connecting.is_terminated() => match session { + Ok(session) => { + let mixer_config = setupp.mixer_config.clone(); + let mixer = (setupp.mixer)(Some(mixer_config)); + let player_config = setupp.player_config.clone(); + let connect_config = setupp.connect_config.clone(); + + let audio_filter = mixer.get_audio_filter(); + let backend = setupp.backend; + let device = setupp.device.clone(); + let (player, event_channel) = + Player::new(player_config, session.clone(), audio_filter, move || { + (backend)(device) + }); + + if setupp.emit_sink_events { + if let Some(player_event_program) = setupp.player_event_program.clone() { + player.set_sink_event_callback(Some(Box::new(move |sink_status| { + match emit_sink_event(sink_status, &player_event_program) { + Ok(e) if e.success() => (), + Ok(e) => { + if let Some(code) = e.code() { + warn!("Sink event prog returned exit code {}", code); + } else { + warn!("Sink event prog returned failure"); + } + } + Err(e) => { + warn!("Emitting sink event failed: {}", e); + } + } + }))); + } + }; + + let (spirc_, spirc_task_) = Spirc::new(connect_config, session, player, mixer); + + spirc = Some(spirc_); + spirc_task = Some(Box::pin(spirc_task_)); + player_event_channel = Some(event_channel); + }, + Err(e) => { + warn!("Connection failed: {}", e); + } + }, + _ = async { spirc_task.as_mut().unwrap().await }, if spirc_task.is_some() => { + spirc_task = None; + + warn!("Spirc shut down unexpectedly"); + while !auto_connect_times.is_empty() + && ((Instant::now() - auto_connect_times[0]).as_secs() > 600) + { + let _ = auto_connect_times.remove(0); + } + + if let Some(credentials) = last_credentials.clone() { + if auto_connect_times.len() >= 5 { + warn!("Spirc shut down too often. Not reconnecting automatically."); + } else { + auto_connect_times.push(Instant::now()); + + connecting = Box::pin(Session::connect( + setupp.session_config.clone(), + credentials, + setupp.cache.clone(), + ).fuse()); + } + } + }, + event = async { player_event_channel.as_mut().unwrap().next().await }, if player_event_channel.is_some() => match event { + Some(event) => { + if let Some(program) = &setupp.player_event_program { + if let Some(child) = run_program_on_events(event, program) { + let mut child = child.expect("program failed to start"); + + tokio::spawn(async move { + match child.wait().await { + Ok(status) if !status.success() => error!("child exited with status {:?}", status.code()), + Err(e) => error!("failed to wait on child process: {}", e), + _ => {} + } + }); + } + } + }, + None => { + player_event_channel = None; + } + }, + _ = tokio::signal::ctrl_c() => { + break; + } + } + } + + info!("Gracefully shutting down"); + + // Shutdown spirc if necessary + if let Some(spirc) = spirc { + spirc.shutdown(); + + if let Some(mut spirc_task) = spirc_task { + tokio::select! { + _ = tokio::signal::ctrl_c() => (), + _ = spirc_task.as_mut() => () + } + } + } +} diff --git a/src/player_event_handler.rs b/src/player_event_handler.rs index 102cf7809..361e6b1ab 100644 --- a/src/player_event_handler.rs +++ b/src/player_event_handler.rs @@ -2,22 +2,12 @@ use librespot::playback::player::PlayerEvent; use log::info; use std::collections::HashMap; use std::io; -use std::process::Command; -use tokio_process::{Child, CommandExt}; +use std::process::{Command, ExitStatus}; -use futures::Future; use librespot::playback::player::SinkStatus; +use tokio::process::{Child as AsyncChild, Command as AsyncCommand}; -fn run_program(program: &str, env_vars: HashMap<&str, String>) -> io::Result { - let mut v: Vec<&str> = program.split_whitespace().collect(); - info!("Running {:?} with environment variables {:?}", v, env_vars); - Command::new(&v.remove(0)) - .args(&v) - .envs(env_vars.iter()) - .spawn_async() -} - -pub fn run_program_on_events(event: PlayerEvent, onevent: &str) -> Option> { +pub fn run_program_on_events(event: PlayerEvent, onevent: &str) -> Option> { let mut env_vars = HashMap::new(); match event { PlayerEvent::Changed { @@ -68,10 +58,18 @@ pub fn run_program_on_events(event: PlayerEvent, onevent: &str) -> Option return None, } - Some(run_program(onevent, env_vars)) + + let mut v: Vec<&str> = onevent.split_whitespace().collect(); + info!("Running {:?} with environment variables {:?}", v, env_vars); + Some( + AsyncCommand::new(&v.remove(0)) + .args(&v) + .envs(env_vars.iter()) + .spawn(), + ) } -pub fn emit_sink_event(sink_status: SinkStatus, onevent: &str) { +pub fn emit_sink_event(sink_status: SinkStatus, onevent: &str) -> io::Result { let mut env_vars = HashMap::new(); env_vars.insert("PLAYER_EVENT", "sink".to_string()); let sink_status = match sink_status { @@ -80,6 +78,12 @@ pub fn emit_sink_event(sink_status: SinkStatus, onevent: &str) { SinkStatus::Closed => "closed", }; env_vars.insert("SINK_STATUS", sink_status.to_string()); + let mut v: Vec<&str> = onevent.split_whitespace().collect(); + info!("Running {:?} with environment variables {:?}", v, env_vars); - let _ = run_program(onevent, env_vars).and_then(|child| child.wait()); + Command::new(&v.remove(0)) + .args(&v) + .envs(env_vars.iter()) + .spawn()? + .wait() } From 1fc5267a71d05f2bc36477041774bfe4d178096a Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Tue, 23 Feb 2021 14:24:03 +0100 Subject: [PATCH 35/75] Revert "Merge pull request #548 from Lcchy/rodiojack-backend" This reverts commit f483075b2cde3e443929873e5abb2f072bac48a3, reversing changes made to ea8ece36d929f3a1e4325139db5a94591ffbf67e. --- COMPILING.md | 1 - Cargo.lock | 824 ++++++++++++---------------- Cargo.toml | 1 - README.md | 1 - playback/Cargo.toml | 1 - playback/src/audio_backend/mod.rs | 20 +- playback/src/audio_backend/rodio.rs | 117 +--- 7 files changed, 358 insertions(+), 607 deletions(-) diff --git a/COMPILING.md b/COMPILING.md index 40eefb395..7b3467eea 100644 --- a/COMPILING.md +++ b/COMPILING.md @@ -46,7 +46,6 @@ Depending on the chosen backend, specific development libraries are required. |PortAudio | `portaudio19-dev` | `portaudio-devel` | `portaudio` | |PulseAudio | `libpulse-dev` | `pulseaudio-libs-devel` | | |JACK | `libjack-dev` | `jack-audio-connection-kit-devel` | | -|JACK over Rodio | `libjack-dev` | `jack-audio-connection-kit-devel` | - | |SDL | `libsdl2-dev` | `SDL2-devel` | | |Pipe | - | - | - | diff --git a/Cargo.lock b/Cargo.lock index efaae37ad..074ecbf84 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,9 +2,9 @@ # It is not intended for manual editing. [[package]] name = "addr2line" -version = "0.14.1" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7" +checksum = "7c0929d69e78dd9bf5408269919fcbcaeb2e35e5d43e5815517cdc6a8e11a423" dependencies = [ "gimli", ] @@ -78,9 +78,9 @@ dependencies = [ [[package]] name = "alsa-sys" -version = "0.3.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527" +checksum = "d5a0559bcd3f7a482690d98be41c08a43e92f669b179433e95ddf5e8b8fd36a3" dependencies = [ "libc", "pkg-config", @@ -88,9 +88,15 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.38" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c0df63cb2955042487fad3aefd2c6e3ae7389ac5dc1beb28921de0b69f779d4" + +[[package]] +name = "arc-swap" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1" +checksum = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034" [[package]] name = "ascii" @@ -111,15 +117,15 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.0.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" [[package]] name = "backtrace" -version = "0.3.56" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d117600f438b1707d4e4ae15d3595657288f8235a0eb593e80ecc98ab34e1bc" +checksum = "ef5140344c85b01f9bbb4d4b7288a8aa4b3287ccef913a14bcc78a1063623598" dependencies = [ "addr2line", "cfg-if 1.0.0", @@ -129,12 +135,6 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "base-x" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" - [[package]] name = "base64" version = "0.9.3" @@ -145,6 +145,21 @@ dependencies = [ "safemem", ] +[[package]] +name = "base64" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" +dependencies = [ + "byteorder", +] + +[[package]] +name = "base64" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" + [[package]] name = "base64" version = "0.13.0" @@ -153,12 +168,13 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] name = "bindgen" -version = "0.56.0" +version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da379dbebc0b76ef63ca68d8fc6e71c0f13e59432e0987e508c1820e6ab5239" +checksum = "c72a978d268b1d70b0e963217e60fdabd9523a941457a6c42a7315d15c7e89e5" dependencies = [ "bitflags", "cexpr", + "cfg-if 0.1.10", "clang-sys", "lazy_static", "lazycell", @@ -181,9 +197,9 @@ dependencies = [ [[package]] name = "bit-vec" -version = "0.6.3" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +checksum = "5f0dc55f2d8a1a85650ac47858bb001b4c0dd73d79e3c455a842925e68d29cd3" [[package]] name = "bitflags" @@ -239,9 +255,9 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" [[package]] name = "bumpalo" -version = "3.6.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099e596ef14349721d9016f6b80dd3419ea1bf289ab9b44df8e4dfd3a005d5d9" +checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" [[package]] name = "byte-tools" @@ -251,9 +267,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "byteorder" -version = "1.4.2" +version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" +checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" [[package]] name = "bytes" @@ -267,15 +283,15 @@ dependencies = [ [[package]] name = "bytes" -version = "1.0.1" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" +checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" [[package]] name = "cc" -version = "1.0.66" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" +checksum = "95752358c8f7552394baf48cd82695b345628ad3f170d607de3ca03b8dacca15" [[package]] name = "cesu8" @@ -306,22 +322,20 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.19" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +checksum = "c74d84029116787153e02106bf53e66828452a4b325cc8652b788b5967c0a0b6" dependencies = [ - "libc", "num-integer", "num-traits", - "time 0.1.43", - "winapi 0.3.9", + "time", ] [[package]] name = "chunked_transfer" -version = "1.4.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e" +checksum = "7477065d45a8fe57167bf3cf8bcd3729b54cfcb81cca49bda2d038ea89ae82ca" [[package]] name = "cipher" @@ -334,13 +348,13 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.0.3" +version = "0.29.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0659001ab56b791be01d4b729c44376edc6718cf389a502e579b77b758f3296c" +checksum = "fe6837df1d5cba2397b835c8530f51723267e16abbf83892e9e5af4f0e5dd10a" dependencies = [ "glob", "libc", - "libloading", + "libloading 0.5.2", ] [[package]] @@ -352,6 +366,15 @@ dependencies = [ "bitflags", ] +[[package]] +name = "cloudabi" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467" +dependencies = [ + "bitflags", +] + [[package]] name = "combine" version = "3.8.1" @@ -367,45 +390,23 @@ dependencies = [ [[package]] name = "combine" -version = "4.5.2" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc4369b5e4c0cddf64ad8981c0111e7df4f7078f4d6ba98fb31f2e17c4c57b7e" +checksum = "b9417a0c314565e2abffaece67e95a8cb51f9238cd39f3764d9dfdf09e72b20c" dependencies = [ - "bytes 1.0.1", + "bytes 0.5.6", "memchr", + "pin-project-lite", ] -[[package]] -name = "const_fn" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6" - [[package]] name = "cookie" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784ad0fbab4f3e9cef09f20e0aea6000ae08d2cb98ac4c0abc53df18803d702f" -dependencies = [ - "percent-encoding 2.1.0", - "time 0.2.25", - "version_check", -] - -[[package]] -name = "cookie_store" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3818dfca4b0cb5211a659bbcbb94225b7127407b2b135e650d717bfb78ab10d3" +checksum = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5" dependencies = [ - "cookie", - "idna 0.2.1", - "log 0.4.14", - "publicsuffix", - "serde", - "serde_json", - "time 0.2.25", - "url 2.2.0", + "time", + "url 1.7.2", ] [[package]] @@ -426,9 +427,9 @@ dependencies = [ [[package]] name = "coreaudio-sys" -version = "0.2.8" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b7e3347be6a09b46aba228d6608386739fb70beff4f61e07422da87b0bb31fa" +checksum = "d6570ee6e089131e928d5ec9236db9e818aa3cf850f48b0eec6ef700571271d4" dependencies = [ "bindgen", ] @@ -442,7 +443,6 @@ dependencies = [ "alsa", "core-foundation-sys", "coreaudio-rs", - "jack", "jni 0.17.0", "js-sys", "lazy_static", @@ -453,7 +453,7 @@ dependencies = [ "nix", "oboe", "parking_lot 0.11.1", - "stdweb 0.1.3", + "stdweb", "thiserror", "web-sys", "winapi 0.3.9", @@ -597,9 +597,9 @@ dependencies = [ [[package]] name = "derivative" -version = "2.2.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +checksum = "cb582b60359da160a9477ee80f15c8d784c477e69c217ef2cdd4169c24ea380f" dependencies = [ "proc-macro2", "quote", @@ -624,12 +624,6 @@ dependencies = [ "generic-array 0.14.4", ] -[[package]] -name = "discard" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" - [[package]] name = "dns-sd" version = "0.1.3" @@ -654,15 +648,15 @@ checksum = "f26ecb66b4bdca6c1409b40fb255eefc2bd4f6d135dab3c3124f80ffa2a9661e" dependencies = [ "atty", "humantime", - "log 0.4.14", + "log 0.4.11", "termcolor", ] [[package]] name = "error-chain" -version = "0.12.4" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" +checksum = "d371106cc88ffdfb1eabd7111e432da544f16f3e2d7bf1dfe8bf575f1df045cd" dependencies = [ "backtrace", "version_check", @@ -676,9 +670,9 @@ checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" [[package]] name = "fetch_unroll" -version = "0.2.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d44807d562d137f063cbfe209da1c3f9f2fa8375e11166ef495daab7b847f9" +checksum = "b5c55005e95bbe15f5f72a73b6597d0dc82ddc97ffe2ca097a99dcd591fefbca" dependencies = [ "libflate", "tar", @@ -687,13 +681,13 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.14" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8" +checksum = "0c122a393ea57648015bf06fbd3d372378992e86b9ff5a7a497b076a28c79efe" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall 0.2.4", + "redox_syscall", "winapi 0.3.9", ] @@ -737,24 +731,24 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" [[package]] name = "futures" -version = "0.1.30" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7e4c2612746b0df8fed4ce0c69156021b704c9aefa360311c04e6e9e002eed" +checksum = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef" [[package]] name = "futures-channel" -version = "0.3.12" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2d31b7ec7efab6eefc7c57233bb10b847986139d88cc2f5a02a1ae6871a1846" +checksum = "f366ad74c28cca6ba456d95e6422883cfb4b252a83bed929c83abfdbbf2967d5" dependencies = [ "futures-core", ] [[package]] name = "futures-core" -version = "0.3.12" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e5145dde8da7d1b3892dad07a9c98fc04bc39892b1ecc9692cf53e2b780a65" +checksum = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399" [[package]] name = "futures-cpupool" @@ -768,9 +762,9 @@ dependencies = [ [[package]] name = "futures-executor" -version = "0.3.12" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9e59fdc009a4b3096bf94f740a0f2424c082521f20a9b08c5c07c48d90fd9b9" +checksum = "10d6bb888be1153d3abeb9006b11b02cf5e9b209fda28693c31ae1e4e012e314" dependencies = [ "futures-core", "futures-task", @@ -779,9 +773,9 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.12" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c287d25add322d9f9abdcdc5927ca398917996600182178774032e9f8258fedd" +checksum = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39" dependencies = [ "proc-macro-hack", "proc-macro2", @@ -791,29 +785,29 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.12" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf5c69029bda2e743fddd0582d1083951d65cc9539aebf8812f36c3491342d6" +checksum = "3f2032893cb734c7a05d85ce0cc8b8c4075278e93b24b66f9de99d6eb0fa8acc" [[package]] name = "futures-task" -version = "0.3.12" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13de07eb8ea81ae445aca7b69f5f7bf15d7bf4912d8ca37d6645c77ae8a58d86" +checksum = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626" dependencies = [ "once_cell", ] [[package]] name = "futures-util" -version = "0.3.12" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632a8cd0f2a4b3fdea1657f08bde063848c3bd00f9bbf6e256b8be78802e624b" +checksum = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6" dependencies = [ "futures-core", "futures-macro", "futures-task", - "pin-project-lite", + "pin-project", "pin-utils", "proc-macro-hack", "proc-macro-nested", @@ -856,24 +850,13 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.16" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" dependencies = [ - "cfg-if 1.0.0", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" -dependencies = [ - "cfg-if 1.0.0", + "cfg-if 0.1.10", "libc", - "wasi 0.10.2+wasi-snapshot-preview1", + "wasi", ] [[package]] @@ -1044,18 +1027,18 @@ dependencies = [ [[package]] name = "heck" -version = "0.3.2" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" +checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" dependencies = [ "unicode-segmentation", ] [[package]] name = "hermit-abi" -version = "0.1.18" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" dependencies = [ "libc", ] @@ -1089,15 +1072,15 @@ dependencies = [ [[package]] name = "httparse" -version = "1.3.5" +version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "615caabe2c3160b313d52ccc905335f4ed5f10881dd63dc5699d47e90be85691" +checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" [[package]] name = "humantime" -version = "2.1.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +checksum = "3c1ad908cc71012b7bea4d0c53ba96a8cba9962f048fa68d143376143d863b7a" [[package]] name = "hyper" @@ -1112,12 +1095,12 @@ dependencies = [ "httparse", "iovec", "language-tags", - "log 0.4.14", + "log 0.4.11", "mime", "net2", "percent-encoding 1.0.1", "relay", - "time 0.1.43", + "time", "tokio-core", "tokio-io", "tokio-proto", @@ -1158,9 +1141,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.2.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de910d521f7cc3135c4de8db1cb910e0b5ed1dc6f57c381cd07e8e661ce10094" +checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" dependencies = [ "matches", "unicode-bidi", @@ -1169,9 +1152,9 @@ dependencies = [ [[package]] name = "if-addrs" -version = "0.6.5" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28538916eb3f3976311f5dfbe67b5362d0add1293d0a9cad17debf86f8e3aa48" +checksum = "f12906406f12abf5569643c46b29aec78313dc1537b17dd5c5250169790c4db9" dependencies = [ "if-addrs-sys", "libc", @@ -1180,9 +1163,9 @@ dependencies = [ [[package]] name = "if-addrs-sys" -version = "0.3.2" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de74b9dd780476e837e5eb5ab7c88b49ed304126e412030a0adba99c8efe79ea" +checksum = "9e2556f16544202bcfe0aa5d20a01a6b815f736b136b3ad76dc547ee6b5bb1df" dependencies = [ "cc", "libc", @@ -1217,9 +1200,9 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.7" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" [[package]] name = "jack" @@ -1235,13 +1218,13 @@ dependencies = [ [[package]] name = "jack-sys" -version = "0.2.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d6ab7ada402b6a27912a2b86504be62a48c58313c886fe72a059127acb4d7" +checksum = "c0d4ca501477fd3cd93a36df581046e5d6338ed826cf7e9b8d302603521e6cc3" dependencies = [ "lazy_static", "libc", - "libloading", + "libloading 0.4.3", ] [[package]] @@ -1254,7 +1237,7 @@ dependencies = [ "combine 3.8.1", "error-chain", "jni-sys", - "log 0.4.14", + "log 0.4.11", "walkdir", ] @@ -1265,10 +1248,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "36bcc950632e48b86da402c5c077590583da5ac0d480103611d5374e7c967a3c" dependencies = [ "cesu8", - "combine 4.5.2", + "combine 4.4.0", "error-chain", "jni-sys", - "log 0.4.14", + "log 0.4.11", "walkdir", ] @@ -1280,9 +1263,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "js-sys" -version = "0.3.47" +version = "0.3.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cfb73131c35423a367daf8cbd24100af0d077668c8c2943f0e7dd775fef0f65" +checksum = "cf3d7383929f7c9c7c2d0fa596f325832df98c3704f2c60553080f7127a58175" dependencies = [ "wasm-bindgen", ] @@ -1311,9 +1294,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "lazycell" -version = "1.3.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" [[package]] name = "lewton" @@ -1323,40 +1306,45 @@ checksum = "777b48df9aaab155475a83a7df3070395ea1ac6902f5cd062b8f2b028075c030" dependencies = [ "byteorder", "ogg", - "tinyvec", + "tinyvec 1.1.1", ] [[package]] name = "libc" -version = "0.2.85" +version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ccac4b00700875e6a07c6cde370d44d32fa01c5a65cdd2fca6858c479d28bb3" +checksum = "bd7d4bd64732af4bf3a67f367c27df8520ad7e230c5817b8ff485864d80242b9" [[package]] name = "libflate" -version = "1.0.3" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389de7875e06476365974da3e7ff85d55f1972188ccd9f6020dd7c8156e17914" +checksum = "d9135df43b1f5d0e333385cb6e7897ecd1a43d7d11b91ac003f4d2c2d2401fdd" dependencies = [ "adler32", "crc32fast", - "libflate_lz77", "rle-decode-fast", + "take_mut", ] [[package]] -name = "libflate_lz77" -version = "1.0.0" +name = "libloading" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3286f09f7d4926fc486334f28d8d2e6ebe4f7f9994494b6dab27ddfad2c9b11b" +checksum = "fd38073de8f7965d0c17d30546d4bb6da311ab428d1c7a3fc71dff7f9d4979b9" +dependencies = [ + "kernel32-sys", + "lazy_static", + "winapi 0.2.8", +] [[package]] name = "libloading" -version = "0.6.7" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883" +checksum = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" dependencies = [ - "cfg-if 1.0.0", + "cc", "winapi 0.3.9", ] @@ -1370,7 +1358,7 @@ dependencies = [ "futures", "hostname", "if-addrs", - "log 0.4.14", + "log 0.4.11", "multimap", "net2", "quick-error", @@ -1380,11 +1368,10 @@ dependencies = [ [[package]] name = "libpulse-binding" -version = "2.23.0" +version = "2.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2405f806801527dfb3d2b6d48a282cdebe9a1b41b0652e0d7b5bad81dbc700e" +checksum = "1e8f85a42300c868de4849bb72eda5a65cea08c3ca61396b72c2d7c28a87f055" dependencies = [ - "bitflags", "libc", "libpulse-sys", "num-derive", @@ -1394,9 +1381,9 @@ dependencies = [ [[package]] name = "libpulse-simple-binding" -version = "2.23.0" +version = "2.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a574975292db859087c3957b9182f7d53278553f06bddaa2099c90e4ac3a0ee0" +checksum = "a047f4502997eed57b3e9d8e71f2b860da91a20bb7e15c65d1f183a7b4fb1226" dependencies = [ "libpulse-binding", "libpulse-simple-sys", @@ -1405,9 +1392,9 @@ dependencies = [ [[package]] name = "libpulse-simple-sys" -version = "1.16.1" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "468cf582b7b022c0d1b266fefc7fc8fa7b1ddcb61214224f2f105c95a9c2d5c1" +checksum = "9b72cb239bc4de6858fa0bbad27419e72cd4466f079ca56f21d94b0a712ab02e" dependencies = [ "libpulse-sys", "pkg-config", @@ -1415,9 +1402,9 @@ dependencies = [ [[package]] name = "libpulse-sys" -version = "1.18.0" +version = "1.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf17e9832643c4f320c42b7d78b2c0510f45aa5e823af094413b94e45076ba82" +checksum = "706e95c4b87ebb81c1e7763c74bf7d5ba897208f1a8aa5fc7bea8298dee8f2ca" dependencies = [ "libc", "num-derive", @@ -1442,7 +1429,7 @@ dependencies = [ "librespot-metadata", "librespot-playback", "librespot-protocol", - "log 0.4.14", + "log 0.4.11", "num-bigint", "protobuf", "rand 0.7.3", @@ -1467,7 +1454,7 @@ dependencies = [ "lewton", "librespot-core", "librespot-tremor", - "log 0.4.14", + "log 0.4.11", "num-bigint", "num-traits", "ogg", @@ -1490,7 +1477,7 @@ dependencies = [ "librespot-core", "librespot-playback", "librespot-protocol", - "log 0.4.14", + "log 0.4.11", "num-bigint", "protobuf", "rand 0.7.3", @@ -1518,7 +1505,7 @@ dependencies = [ "hyper-proxy", "lazy_static", "librespot-protocol", - "log 0.4.14", + "log 0.4.11", "num-bigint", "num-integer", "num-traits", @@ -1547,7 +1534,7 @@ dependencies = [ "librespot-core", "librespot-protocol", "linear-map", - "log 0.4.14", + "log 0.4.11", "protobuf", ] @@ -1569,7 +1556,7 @@ dependencies = [ "librespot-audio", "librespot-core", "librespot-metadata", - "log 0.4.14", + "log 0.4.11", "portaudio-rs", "rodio", "sdl2", @@ -1629,16 +1616,16 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" dependencies = [ - "log 0.4.14", + "log 0.4.11", ] [[package]] name = "log" -version = "0.4.14" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" dependencies = [ - "cfg-if 1.0.0", + "cfg-if 0.1.10", ] [[package]] @@ -1670,15 +1657,15 @@ checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" [[package]] name = "memchr" -version = "2.3.4" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" +checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" [[package]] name = "memoffset" -version = "0.5.6" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" +checksum = "c198b026e1bbf08a937e94c6c60f9ec4a2267f5b0d2eec9c1b21b061ce2be55f" dependencies = [ "autocfg", ] @@ -1701,9 +1688,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.6.23" +version = "0.6.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" +checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430" dependencies = [ "cfg-if 0.1.10", "fuchsia-zircon", @@ -1711,8 +1698,8 @@ dependencies = [ "iovec", "kernel32-sys", "libc", - "log 0.4.14", - "miow 0.2.2", + "log 0.4.11", + "miow 0.2.1", "net2", "slab 0.4.2", "winapi 0.2.8", @@ -1724,9 +1711,9 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656" dependencies = [ - "log 0.4.14", + "log 0.4.11", "mio", - "miow 0.3.6", + "miow 0.3.5", "winapi 0.3.9", ] @@ -1743,9 +1730,9 @@ dependencies = [ [[package]] name = "miow" -version = "0.2.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" +checksum = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" dependencies = [ "kernel32-sys", "net2", @@ -1755,9 +1742,9 @@ dependencies = [ [[package]] name = "miow" -version = "0.3.6" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897" +checksum = "07b88fb9795d4d36d62a012dfbf49a8f5cf12751f36d31a9dbe66d528e58979e" dependencies = [ "socket2", "winapi 0.3.9", @@ -1771,9 +1758,9 @@ checksum = "0419348c027fa7be448d2ae7ea0e4e04c2334c31dc4e74ab29f00a2a7ca69204" [[package]] name = "multimap" -version = "0.8.2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1255076139a83bb467426e7f8d0134968a8118844faa755985e077cf31850333" +checksum = "d8883adfde9756c1d30b0f519c9b8c502a94b41ac62f696453c37c7fc0a958ce" dependencies = [ "serde", ] @@ -1798,7 +1785,7 @@ checksum = "bdf399b8b7a39c6fb153c4ec32c72fd5fe789df24a647f229c239aa7adb15241" dependencies = [ "lazy_static", "libc", - "log 0.4.14", + "log 0.4.11", "ndk", "ndk-macro", "ndk-sys", @@ -1825,9 +1812,9 @@ checksum = "c44922cb3dbb1c70b5e5f443d63b64363a898564d739ba5198e3a9138442868d" [[package]] name = "net2" -version = "0.2.37" +version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" +checksum = "2ba7c918ac76704fb42afcbbb43891e72731f3dcca3bef2a19786297baf14af7" dependencies = [ "cfg-if 0.1.10", "libc", @@ -1881,9 +1868,9 @@ dependencies = [ [[package]] name = "num-integer" -version = "0.1.44" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b" dependencies = [ "autocfg", "num-traits", @@ -1902,9 +1889,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.14" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" dependencies = [ "autocfg", ] @@ -1943,9 +1930,9 @@ dependencies = [ [[package]] name = "object" -version = "0.23.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4" +checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" [[package]] name = "oboe" @@ -2027,7 +2014,7 @@ checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" dependencies = [ "instant", "lock_api 0.4.2", - "parking_lot_core 0.8.2", + "parking_lot_core 0.8.0", ] [[package]] @@ -2037,25 +2024,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" dependencies = [ "cfg-if 0.1.10", - "cloudabi", + "cloudabi 0.0.3", "libc", - "redox_syscall 0.1.57", + "redox_syscall", "rustc_version", - "smallvec 0.6.14", + "smallvec 0.6.13", "winapi 0.3.9", ] [[package]] name = "parking_lot_core" -version = "0.8.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ccb628cad4f84851442432c60ad8e1f607e29752d0bf072cbd0baf28aa34272" +checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b" dependencies = [ - "cfg-if 1.0.0", + "cfg-if 0.1.10", + "cloudabi 0.1.0", "instant", "libc", - "redox_syscall 0.1.57", - "smallvec 1.6.1", + "redox_syscall", + "smallvec 1.5.0", "winapi 0.3.9", ] @@ -2093,11 +2081,31 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +[[package]] +name = "pin-project" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12e3a6cdbfe94a5e4572812a0201f8c0ed98c1c452c7b8563ce2276988ef9c17" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a0ffd45cf79d88737d7cc85bfd5d2894bee1139b356e616fe85dc389c61aaf7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "pin-project-lite" -version = "0.2.4" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827" +checksum = "c917123afa01924fc84bb20c4c03f004d9c38e5127e3c039bbf7f4b9c76a2f6b" [[package]] name = "pin-utils" @@ -2107,9 +2115,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.19" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" +checksum = "d36492546b6af1463394d46f0c834346f31548646f6ba10849802c9c9a27ac33" [[package]] name = "portaudio-rs" @@ -2134,9 +2142,9 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.10" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" [[package]] name = "pretty-hex" @@ -2179,21 +2187,21 @@ dependencies = [ [[package]] name = "proc-macro-hack" -version = "0.5.19" +version = "0.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" +checksum = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4" [[package]] name = "proc-macro-nested" -version = "0.1.7" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" +checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" [[package]] name = "proc-macro2" -version = "1.0.24" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12" dependencies = [ "unicode-xid", ] @@ -2223,19 +2231,6 @@ dependencies = [ "protobuf-codegen", ] -[[package]] -name = "publicsuffix" -version = "1.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bbaa49075179162b49acac1c6aa45fb4dafb5f13cf6794276d77bc7fd95757b" -dependencies = [ - "error-chain", - "idna 0.2.1", - "lazy_static", - "regex", - "url 2.2.0", -] - [[package]] name = "qstring" version = "0.7.2" @@ -2253,9 +2248,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.8" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" dependencies = [ "proc-macro2", ] @@ -2289,23 +2284,11 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom 0.1.16", + "getrandom", "libc", - "rand_chacha 0.2.2", + "rand_chacha", "rand_core 0.5.1", - "rand_hc 0.2.0", -] - -[[package]] -name = "rand" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" -dependencies = [ - "libc", - "rand_chacha 0.3.0", - "rand_core 0.6.1", - "rand_hc 0.3.0", + "rand_hc", ] [[package]] @@ -2318,16 +2301,6 @@ dependencies = [ "rand_core 0.5.1", ] -[[package]] -name = "rand_chacha" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.1", -] - [[package]] name = "rand_core" version = "0.3.1" @@ -2349,16 +2322,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom 0.1.16", -] - -[[package]] -name = "rand_core" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5" -dependencies = [ - "getrandom 0.2.2", + "getrandom", ] [[package]] @@ -2370,15 +2334,6 @@ dependencies = [ "rand_core 0.5.1", ] -[[package]] -name = "rand_hc" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" -dependencies = [ - "rand_core 0.6.1", -] - [[package]] name = "rdrand" version = "0.4.0" @@ -2394,29 +2349,20 @@ version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" -[[package]] -name = "redox_syscall" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570" -dependencies = [ - "bitflags", -] - [[package]] name = "regex" -version = "1.4.3" +version = "1.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a" +checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" dependencies = [ "regex-syntax", ] [[package]] name = "regex-syntax" -version = "0.6.22" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581" +checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" [[package]] name = "relay" @@ -2438,9 +2384,9 @@ dependencies = [ [[package]] name = "ring" -version = "0.16.20" +version = "0.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +checksum = "70017ed5c555d79ee3538fc63ca09c70ad8f317dcadc1adc2c496b60c22bb24f" dependencies = [ "cc", "libc", @@ -2468,9 +2414,9 @@ dependencies = [ [[package]] name = "rpassword" -version = "5.0.1" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc936cf8a7ea60c58f030fd36a612a48f440610214dc54bc36431f9ea0c3efb" +checksum = "d755237fc0f99d98641540e66abac8bc46a0652f19148ac9e21de2da06b326c9" dependencies = [ "libc", "winapi 0.3.9", @@ -2499,12 +2445,12 @@ dependencies = [ [[package]] name = "rustls" -version = "0.19.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "064fd21ff87c6e87ed4506e68beb42459caa4a0e2eb144932e6776768556980b" +checksum = "b25a18b1bf7387f0145e7f8324e700805aade3842dd3db2e74e4cdeb4677c09e" dependencies = [ - "base64 0.13.0", - "log 0.4.14", + "base64 0.10.1", + "log 0.4.11", "ring", "sct", "webpki", @@ -2593,18 +2539,15 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.123" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae" -dependencies = [ - "serde_derive", -] +checksum = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3" [[package]] name = "serde_derive" -version = "1.0.123" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31" +checksum = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e" dependencies = [ "proc-macro2", "quote", @@ -2613,9 +2556,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.61" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a" +checksum = "3433e879a558dde8b5e8feb2a04899cf34fdde1fafb894687e52105fc1162ac3" dependencies = [ "itoa", "ryu", @@ -2647,12 +2590,6 @@ dependencies = [ "opaque-debug 0.3.0", ] -[[package]] -name = "sha1" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" - [[package]] name = "shannon" version = "0.2.0" @@ -2676,10 +2613,11 @@ checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" [[package]] name = "signal-hook-registry" -version = "1.3.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6" +checksum = "94f478ede9f64724c5d173d7bb56099ec3e2d9fc2774aac65d34b8b890405f41" dependencies = [ + "arc-swap", "libc", ] @@ -2703,27 +2641,28 @@ checksum = "4c8cbcd6df1e117c2210e13ab5109635ad68a929fcbb8964dc965b76cb5ee013" [[package]] name = "smallvec" -version = "0.6.14" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0" +checksum = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" dependencies = [ "maybe-uninit", ] [[package]] name = "smallvec" -version = "1.6.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" +checksum = "7acad6f34eb9e8a259d3283d1e8c1d34d7415943d4895f65cc73813c7396fc85" [[package]] name = "socket2" -version = "0.3.19" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" +checksum = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" dependencies = [ - "cfg-if 1.0.0", + "cfg-if 0.1.10", "libc", + "redox_syscall", "winapi 0.3.9", ] @@ -2733,70 +2672,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" -[[package]] -name = "standback" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2beb4d1860a61f571530b3f855a1b538d0200f7871c63331ecd6f17b1f014f8" -dependencies = [ - "version_check", -] - [[package]] name = "stdweb" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e" -[[package]] -name = "stdweb" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" -dependencies = [ - "discard", - "rustc_version", - "stdweb-derive", - "stdweb-internal-macros", - "stdweb-internal-runtime", - "wasm-bindgen", -] - -[[package]] -name = "stdweb-derive" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "serde_derive", - "syn", -] - -[[package]] -name = "stdweb-internal-macros" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" -dependencies = [ - "base-x", - "proc-macro2", - "quote", - "serde", - "serde_derive", - "serde_json", - "sha1", - "syn", -] - -[[package]] -name = "stdweb-internal-runtime" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" - [[package]] name = "strsim" version = "0.9.3" @@ -2829,9 +2710,9 @@ checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" [[package]] name = "syn" -version = "1.0.60" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" +checksum = "fb7f4c519df8c117855e19dd8cc851e89eb746fe7a73f0157e0d95fdec5369b0" dependencies = [ "proc-macro2", "quote", @@ -2871,54 +2752,61 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b157868d8ac1f56b64604539990685fa7611d8fa9e5476cf0c02cf34d32917c5" +[[package]] +name = "take_mut" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" + [[package]] name = "tar" -version = "0.4.32" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0313546c01d59e29be4f09687bcb4fb6690cec931cc3607b6aec7a0e417f4cc6" +checksum = "489997b7557e9a43e192c527face4feacc78bfbe6eed67fd55c4c9e381cba290" dependencies = [ "filetime", "libc", + "redox_syscall", "xattr", ] [[package]] name = "tempfile" -version = "3.2.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" dependencies = [ - "cfg-if 1.0.0", + "cfg-if 0.1.10", "libc", - "rand 0.8.3", - "redox_syscall 0.2.4", + "rand 0.7.3", + "redox_syscall", "remove_dir_all", "winapi 0.3.9", ] [[package]] name = "termcolor" -version = "1.1.2" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" dependencies = [ "winapi-util", ] [[package]] name = "thiserror" -version = "1.0.23" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76cc616c6abf8c8928e2fdcc0dbfab37175edd8fb49a4641066ad1364fdab146" +checksum = "318234ffa22e0920fe9a40d7b8369b5f649d490980cf7aadcf1eb91594869b42" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.23" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1" +checksum = "cae2447b6282786c3493999f40a9be2a6ad20cb8bd268b0a0dbf5a065535c0ab" dependencies = [ "proc-macro2", "quote", @@ -2936,42 +2824,10 @@ dependencies = [ ] [[package]] -name = "time" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1195b046942c221454c2539395f85413b33383a067449d78aab2b7b052a142f7" -dependencies = [ - "const_fn", - "libc", - "standback", - "stdweb 0.4.20", - "time-macros", - "version_check", - "winapi 0.3.9", -] - -[[package]] -name = "time-macros" -version = "0.1.1" +name = "tinyvec" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" -dependencies = [ - "proc-macro-hack", - "time-macros-impl", -] - -[[package]] -name = "time-macros-impl" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5c3be1edfad6027c69f5491cf4cb310d1a71ecd6af742788c6ff8bced86b8fa" -dependencies = [ - "proc-macro-hack", - "proc-macro2", - "quote", - "standback", - "syn", -] +checksum = "53953d2d3a5ad81d9f844a32f14ebb121f50b650cd59d0ee2a07cf13c617efed" [[package]] name = "tinyvec" @@ -3025,14 +2881,14 @@ dependencies = [ [[package]] name = "tokio-core" -version = "0.1.18" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87b1395334443abca552f63d4f61d0486f12377c2ba8b368e523f89e828cffd4" +checksum = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71" dependencies = [ "bytes 0.4.12", "futures", "iovec", - "log 0.4.14", + "log 0.4.11", "mio", "scoped-tls", "tokio", @@ -3081,7 +2937,7 @@ checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" dependencies = [ "bytes 0.4.12", "futures", - "log 0.4.14", + "log 0.4.11", ] [[package]] @@ -3094,7 +2950,7 @@ dependencies = [ "futures", "lazy_static", "libc", - "log 0.4.14", + "log 0.4.11", "mio", "mio-named-pipes", "tokio-io", @@ -3130,7 +2986,7 @@ dependencies = [ "crossbeam-utils 0.7.2", "futures", "lazy_static", - "log 0.4.14", + "log 0.4.11", "mio", "num_cpus", "parking_lot 0.9.0", @@ -3201,7 +3057,7 @@ dependencies = [ "crossbeam-utils 0.7.2", "futures", "lazy_static", - "log 0.4.14", + "log 0.4.11", "num_cpus", "slab 0.4.2", "tokio-executor", @@ -3227,7 +3083,7 @@ checksum = "e2a0b10e610b39c38b031a2fcab08e4b82f16ece36504988dcbd81dbba650d82" dependencies = [ "bytes 0.4.12", "futures", - "log 0.4.14", + "log 0.4.11", "mio", "tokio-codec", "tokio-io", @@ -3244,7 +3100,7 @@ dependencies = [ "futures", "iovec", "libc", - "log 0.4.14", + "log 0.4.11", "mio", "mio-uds", "tokio-codec", @@ -3254,9 +3110,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.8" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +checksum = "75cf45bb0bef80604d001caaec0d09da99611b3c0fd39d3080468875cdb65645" dependencies = [ "serde", ] @@ -3293,11 +3149,11 @@ dependencies = [ [[package]] name = "unicode-normalization" -version = "0.1.16" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a13e63ab62dbe32aeee58d1c5408d35c36c392bba5d9d3142287219721afe606" +checksum = "6fb19cf769fa8c6a80a162df694621ebeb4dafb606470b2b2fce0be40a98a977" dependencies = [ - "tinyvec", + "tinyvec 0.3.3", ] [[package]] @@ -3335,16 +3191,14 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "ureq" -version = "1.5.4" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "294b85ef5dbc3670a72e82a89971608a1fcc4ed5c7c5a2895230d31a95f0569b" +checksum = "801125e6d1ba6864cf3a5a92cfb2f0b0a3ee73e40602a0cd206ad2f3c040aa96" dependencies = [ - "base64 0.13.0", + "base64 0.11.0", "chunked_transfer", "cookie", - "cookie_store", - "log 0.4.14", - "once_cell", + "lazy_static", "qstring", "rustls", "url 2.2.0", @@ -3370,18 +3224,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5909f2b0817350449ed73e8bcd81c8c3c8d9a7a5d8acba4b27db277f1868976e" dependencies = [ "form_urlencoded", - "idna 0.2.1", + "idna 0.2.0", "matches", "percent-encoding 2.1.0", ] [[package]] name = "uuid" -version = "0.8.2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +checksum = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11" dependencies = [ - "getrandom 0.2.2", + "rand 0.7.3", ] [[package]] @@ -3426,11 +3280,11 @@ dependencies = [ [[package]] name = "vorbis-sys" -version = "0.1.1" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9ed6ef5361a85e68ccc005961d995c2d44e31f0816f142025f2ca2383dfbfd" +checksum = "3a0a8d7034313748da1d84b0adfa501f83f9ec83250f37fbacfa92a3580327c4" dependencies = [ - "cc", + "gcc", "libc", "ogg-sys", "pkg-config", @@ -3467,7 +3321,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a05d9d966753fa4b5c8db73fcab5eed4549cfe0e1e4e66911e5564a0085c35d1" dependencies = [ "futures", - "log 0.4.14", + "log 0.4.11", "try-lock", ] @@ -3477,17 +3331,11 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" -[[package]] -name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" - [[package]] name = "wasm-bindgen" -version = "0.2.70" +version = "0.2.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55c0f7123de74f0dab9b7d00fd614e7b19349cd1e2f5252bbe9b1754b59433be" +checksum = "3cd364751395ca0f68cafb17666eee36b63077fb5ecd972bbcd74c90c4bf736e" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -3495,13 +3343,13 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.70" +version = "0.2.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bc45447f0d4573f3d65720f636bbcc3dd6ce920ed704670118650bcd47764c7" +checksum = "1114f89ab1f4106e5b55e688b828c0ab0ea593a1ea7c094b141b14cbaaec2d62" dependencies = [ "bumpalo", "lazy_static", - "log 0.4.14", + "log 0.4.11", "proc-macro2", "quote", "syn", @@ -3510,9 +3358,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.70" +version = "0.2.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b8853882eef39593ad4174dd26fc9865a64e84026d223f63bb2c42affcbba2c" +checksum = "7a6ac8995ead1f084a8dea1e65f194d0973800c7f571f6edd70adf06ecf77084" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3520,9 +3368,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.70" +version = "0.2.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4133b5e7f2a531fa413b3a1695e925038a05a71cf67e87dafa295cb645a01385" +checksum = "b5a48c72f299d80557c7c62e37e7225369ecc0c963964059509fbafe917c7549" dependencies = [ "proc-macro2", "quote", @@ -3533,15 +3381,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.70" +version = "0.2.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4945e4943ae02d15c13962b38a5b1e81eadd4b71214eee75af64a4d6a4fd64" +checksum = "7e7811dd7f9398f14cc76efd356f98f03aa30419dea46aa810d71e819fc97158" [[package]] name = "web-sys" -version = "0.3.47" +version = "0.3.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c40dc691fc48003eba817c38da7113c15698142da971298003cac3ef175680b3" +checksum = "222b1ef9334f92a21d3fb53dc3fd80f30836959a90f9274a626d7e06315ba3c3" dependencies = [ "js-sys", "wasm-bindgen", @@ -3549,9 +3397,9 @@ dependencies = [ [[package]] name = "webpki" -version = "0.21.4" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" +checksum = "ab146130f5f790d45f82aeeb09e55a256573373ec64409fc19a6fb82fb1032ae" dependencies = [ "ring", "untrusted", @@ -3559,9 +3407,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.21.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82015b7e0b8bad8185994674a13a93306bea76cf5a16c5a181382fd3a5ec2376" +checksum = "91cd5736df7f12a964a5067a12c62fa38e1bd8080aff1f80bc29be7c80d19ab4" dependencies = [ "webpki", ] diff --git a/Cargo.toml b/Cargo.toml index 0b2545922..a898b40d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,7 +63,6 @@ alsa-backend = ["librespot-playback/alsa-backend"] portaudio-backend = ["librespot-playback/portaudio-backend"] pulseaudio-backend = ["librespot-playback/pulseaudio-backend"] jackaudio-backend = ["librespot-playback/jackaudio-backend"] -rodiojack-backend = ["librespot-playback/rodiojack-backend"] rodio-backend = ["librespot-playback/rodio-backend"] sdl-backend = ["librespot-playback/sdl-backend"] gstreamer-backend = ["librespot-playback/gstreamer-backend"] diff --git a/README.md b/README.md index 33b2b76e2..e7611aa80 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,6 @@ ALSA PortAudio PulseAudio JACK -JACK over Rodio SDL Pipe ``` diff --git a/playback/Cargo.toml b/playback/Cargo.toml index b8995a4bc..69dcc3c33 100644 --- a/playback/Cargo.toml +++ b/playback/Cargo.toml @@ -42,7 +42,6 @@ alsa-backend = ["alsa"] portaudio-backend = ["portaudio-rs"] pulseaudio-backend = ["libpulse-binding", "libpulse-simple-binding"] jackaudio-backend = ["jack"] -rodiojack-backend = ["rodio", "cpal/jack"] rodio-backend = ["rodio", "cpal"] sdl-backend = ["sdl2"] gstreamer-backend = ["gstreamer", "gstreamer-app", "glib", "zerocopy"] diff --git a/playback/src/audio_backend/mod.rs b/playback/src/audio_backend/mod.rs index 3f5dae8d4..6bda39335 100644 --- a/playback/src/audio_backend/mod.rs +++ b/playback/src/audio_backend/mod.rs @@ -35,28 +35,15 @@ mod jackaudio; #[cfg(feature = "jackaudio-backend")] use self::jackaudio::JackSink; -#[cfg(all( - feature = "rodiojack-backend", - not(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd")) -))] -compile_error!("Rodio JACK backend is currently only supported on linux."); - -#[cfg(all( - feature = "rodiojack-backend", - any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd") -))] -use self::rodio::JackRodioSink; - #[cfg(feature = "gstreamer-backend")] mod gstreamer; #[cfg(feature = "gstreamer-backend")] use self::gstreamer::GstreamerSink; -#[cfg(any(feature = "rodio-backend", feature = "rodiojack-backend"))] +#[cfg(feature = "rodio-backend")] mod rodio; #[cfg(feature = "rodio-backend")] use self::rodio::RodioSink; - #[cfg(feature = "sdl-backend")] mod sdl; #[cfg(feature = "sdl-backend")] @@ -77,11 +64,6 @@ pub const BACKENDS: &'static [(&'static str, fn(Option) -> Box ("pulseaudio", mk_sink::), #[cfg(feature = "jackaudio-backend")] ("jackaudio", mk_sink::), - #[cfg(all( - feature = "rodiojack-backend", - any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd") - ))] - ("rodiojack", mk_sink::), #[cfg(feature = "gstreamer-backend")] ("gstreamer", mk_sink::), #[cfg(feature = "rodio-backend")] diff --git a/playback/src/audio_backend/rodio.rs b/playback/src/audio_backend/rodio.rs index 3b920c302..b20c53be0 100644 --- a/playback/src/audio_backend/rodio.rs +++ b/playback/src/audio_backend/rodio.rs @@ -13,17 +13,6 @@ pub struct RodioSink { stream: rodio::OutputStream, } -#[cfg(all( - feature = "rodiojack-backend", - any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd") -))] -pub struct JackRodioSink { - jackrodio_sink: rodio::Sink, - // We have to keep hold of this object, or the Sink can't play... - #[allow(dead_code)] - stream: rodio::OutputStream, -} - fn list_formats(ref device: &rodio::Device) { let default_fmt = match device.default_output_config() { Ok(fmt) => cpal::SupportedStreamConfig::from(fmt), @@ -51,19 +40,17 @@ fn list_formats(ref device: &rodio::Device) { } } -fn list_outputs(ref host: &cpal::Host) { - let default_device = get_default_device(host); +fn list_outputs() { + let default_device = get_default_device(); let default_device_name = default_device.name().expect("cannot get output name"); println!("Default Audio Device:\n {}", default_device_name); list_formats(&default_device); println!("Other Available Audio Devices:"); - - let found_devices = host.output_devices().expect(&format!( - "Cannot get list of output devices of Host: {:?}", - host.id() - )); - for device in found_devices { + for device in cpal::default_host() + .output_devices() + .expect("cannot get list of output devices") + { let device_name = device.name().expect("cannot get output name"); if device_name != default_device_name { println!(" {}", device_name); @@ -72,24 +59,23 @@ fn list_outputs(ref host: &cpal::Host) { } } -fn get_default_device(ref host: &cpal::Host) -> rodio::Device { - host.default_output_device() +fn get_default_device() -> rodio::Device { + cpal::default_host() + .default_output_device() .expect("no default output device available") } -fn match_device(ref host: &cpal::Host, device: Option) -> rodio::Device { +fn match_device(device: Option) -> rodio::Device { match device { Some(device_name) => { if device_name == "?".to_string() { - list_outputs(host); + list_outputs(); exit(0) } - - let found_devices = host.output_devices().expect(&format!( - "Cannot get list of output devices of Host: {:?}", - host.id() - )); - for d in found_devices { + for d in cpal::default_host() + .output_devices() + .expect("cannot get list of output devices") + { if d.name().expect("cannot get output name") == device_name { return d; } @@ -97,16 +83,18 @@ fn match_device(ref host: &cpal::Host, device: Option) -> rodio::Device println!("No output sink matching '{}' found.", device_name); exit(0) } - None => return get_default_device(host), + None => return get_default_device(), } } impl Open for RodioSink { fn open(device: Option) -> RodioSink { - let host = cpal::default_host(); - debug!("Using rodio sink with cpal host: {:?}", host.id()); + debug!( + "Using rodio sink with cpal host: {:?}", + cpal::default_host().id() + ); - let rodio_device = match_device(&host, device); + let rodio_device = match_device(device); debug!("Using cpal device"); let stream = rodio::OutputStream::try_from_device(&rodio_device) .expect("Couldn't open output stream."); @@ -121,36 +109,6 @@ impl Open for RodioSink { } } -#[cfg(all( - feature = "rodiojack-backend", - any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd") -))] -impl Open for JackRodioSink { - fn open(device: Option) -> JackRodioSink { - let host = cpal::host_from_id( - cpal::available_hosts() - .into_iter() - .find(|id| *id == cpal::HostId::Jack) - .expect("Jack Host not found"), - ) - .expect("Jack Host not found"); - debug!("Using jack rodio sink with cpal Jack host"); - - let rodio_device = match_device(&host, device); - debug!("Using cpal device"); - let stream = rodio::OutputStream::try_from_device(&rodio_device) - .expect("Couldn't open output stream."); - debug!("Using jack rodio stream"); - let sink = rodio::Sink::try_new(&stream.1).expect("Couldn't create output sink."); - debug!("Using jack rodio sink"); - - JackRodioSink { - jackrodio_sink: sink, - stream: stream.0, - } - } -} - impl Sink for RodioSink { fn start(&mut self) -> io::Result<()> { // More similar to an "unpause" than "play". Doesn't undo "stop". @@ -179,36 +137,3 @@ impl Sink for RodioSink { Ok(()) } } - -#[cfg(all( - feature = "rodiojack-backend", - any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd") -))] -impl Sink for JackRodioSink { - fn start(&mut self) -> io::Result<()> { - // More similar to an "unpause" than "play". Doesn't undo "stop". - // self.rodio_sink.play(); - Ok(()) - } - - fn stop(&mut self) -> io::Result<()> { - // This will immediately stop playback, but the sink is then unusable. - // We just have to let the current buffer play till the end. - // self.rodio_sink.stop(); - Ok(()) - } - - fn write(&mut self, data: &[i16]) -> io::Result<()> { - let source = rodio::buffer::SamplesBuffer::new(2, 44100, data); - self.jackrodio_sink.append(source); - - // Chunk sizes seem to be about 256 to 3000 ish items long. - // Assuming they're on average 1628 then a half second buffer is: - // 44100 elements --> about 27 chunks - while self.jackrodio_sink.len() > 26 { - // sleep and wait for rodio to drain a bit - thread::sleep(time::Duration::from_millis(10)); - } - Ok(()) - } -} From c0942f14e8868c3c0836438ed1d92cc698c8d38c Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Tue, 23 Feb 2021 15:05:02 +0100 Subject: [PATCH 36/75] Restore rodiojack support Probably more simple than the previous approach which doubles the code: Instead of implementing the `Open` trait, we simply use custom SinkBuilder, one for the default host, and one for the "jack" host. --- .github/workflows/test.yml | 1 + COMPILING.md | 1 + Cargo.lock | 1 + Cargo.toml | 1 + README.md | 1 + playback/Cargo.toml | 1 + playback/src/audio_backend/mod.rs | 9 +-- playback/src/audio_backend/rodio.rs | 92 +++++++++++++++++------------ 8 files changed, 64 insertions(+), 43 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4ad4b406a..c20fe1c68 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -78,6 +78,7 @@ jobs: - run: cargo build --locked --no-default-features --features "portaudio-backend" - run: cargo build --locked --no-default-features --features "pulseaudio-backend" - run: cargo build --locked --no-default-features --features "jackaudio-backend" + - run: cargo build --locked --no-default-features --features "rodiojack-backend" - run: cargo build --locked --no-default-features --features "rodio-backend" - run: cargo build --locked --no-default-features --features "sdl-backend" - run: cargo build --locked --no-default-features --features "gstreamer-backend" diff --git a/COMPILING.md b/COMPILING.md index 7b3467eea..40eefb395 100644 --- a/COMPILING.md +++ b/COMPILING.md @@ -46,6 +46,7 @@ Depending on the chosen backend, specific development libraries are required. |PortAudio | `portaudio19-dev` | `portaudio-devel` | `portaudio` | |PulseAudio | `libpulse-dev` | `pulseaudio-libs-devel` | | |JACK | `libjack-dev` | `jack-audio-connection-kit-devel` | | +|JACK over Rodio | `libjack-dev` | `jack-audio-connection-kit-devel` | - | |SDL | `libsdl2-dev` | `SDL2-devel` | | |Pipe | - | - | - | diff --git a/Cargo.lock b/Cargo.lock index 33dbb922b..1e8176f62 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -433,6 +433,7 @@ dependencies = [ "alsa", "core-foundation-sys", "coreaudio-rs", + "jack", "jni 0.17.0", "js-sys", "lazy_static", diff --git a/Cargo.toml b/Cargo.toml index 21c010c90..d34189ec3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -66,6 +66,7 @@ portaudio-backend = ["librespot-playback/portaudio-backend"] pulseaudio-backend = ["librespot-playback/pulseaudio-backend"] jackaudio-backend = ["librespot-playback/jackaudio-backend"] rodio-backend = ["librespot-playback/rodio-backend"] +rodiojack-backend = ["librespot-playback/rodiojack-backend"] sdl-backend = ["librespot-playback/sdl-backend"] gstreamer-backend = ["librespot-playback/gstreamer-backend"] diff --git a/README.md b/README.md index e7611aa80..7102c28a0 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ ALSA PortAudio PulseAudio JACK +JACK over Rodio SDL Pipe ``` diff --git a/playback/Cargo.toml b/playback/Cargo.toml index acb20c46d..2759ae0e4 100644 --- a/playback/Cargo.toml +++ b/playback/Cargo.toml @@ -46,5 +46,6 @@ portaudio-backend = ["portaudio-rs"] pulseaudio-backend = ["libpulse-binding", "libpulse-simple-binding"] jackaudio-backend = ["jack"] rodio-backend = ["rodio", "cpal", "thiserror"] +rodiojack-backend = ["rodio", "cpal/jack", "thiserror"] sdl-backend = ["sdl2"] gstreamer-backend = ["gstreamer", "gstreamer-app", "glib", "zerocopy"] diff --git a/playback/src/audio_backend/mod.rs b/playback/src/audio_backend/mod.rs index 50031a40f..214ede8c3 100644 --- a/playback/src/audio_backend/mod.rs +++ b/playback/src/audio_backend/mod.rs @@ -42,10 +42,9 @@ mod gstreamer; #[cfg(feature = "gstreamer-backend")] use self::gstreamer::GstreamerSink; -#[cfg(feature = "rodio-backend")] +#[cfg(any(feature = "rodio-backend", feature = "rodiojack-backend"))] mod rodio; -#[cfg(feature = "rodio-backend")] -use self::rodio::RodioSink; + #[cfg(feature = "sdl-backend")] mod sdl; #[cfg(feature = "sdl-backend")] @@ -69,7 +68,9 @@ pub const BACKENDS: &'static [(&'static str, SinkBuilder)] = &[ #[cfg(feature = "gstreamer-backend")] ("gstreamer", mk_sink::), #[cfg(feature = "rodio-backend")] - ("rodio", mk_sink::), + ("rodio", rodio::mk_rodio), + #[cfg(feature = "rodiojack-backend")] + ("rodiojack", rodio::mk_rodiojack), #[cfg(feature = "sdl-backend")] ("sdl", mk_sink::), ("pipe", mk_sink::), diff --git a/playback/src/audio_backend/rodio.rs b/playback/src/audio_backend/rodio.rs index 1b7a8b8a2..56e19b61d 100644 --- a/playback/src/audio_backend/rodio.rs +++ b/playback/src/audio_backend/rodio.rs @@ -5,9 +5,28 @@ use std::{io, thread, time}; use cpal::traits::{DeviceTrait, HostTrait}; use thiserror::Error; -use super::{Open, Sink}; +use super::Sink; use crate::audio::AudioPacket; +#[cfg(all( + feature = "rodiojack-backend", + not(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd")) +))] +compile_error!("Rodio JACK backend is currently only supported on linux."); + +#[cfg(feature = "rodio-backend")] +pub fn mk_rodio(device: Option) -> Box { + Box::new(open(cpal::default_host(), device)) +} + +#[cfg(feature = "rodiojack-backend")] +pub fn mk_rodiojack(device: Option) -> Box { + Box::new(open( + cpal::host_from_id(cpal::HostId::Jack).unwrap(), + device, + )) +} + #[derive(Debug, Error)] pub enum RodioError { #[error("Rodio: no device available")] @@ -60,10 +79,10 @@ fn list_formats(device: &rodio::Device) { } } -fn list_outputs() -> Result<(), cpal::DevicesError> { +fn list_outputs(host: &cpal::Host) -> Result<(), cpal::DevicesError> { let mut default_device_name = None; - if let Some(default_device) = get_default_device() { + if let Some(default_device) = host.default_output_device() { default_device_name = default_device.name().ok(); println!( "Default Audio Device:\n {}", @@ -77,7 +96,7 @@ fn list_outputs() -> Result<(), cpal::DevicesError> { warn!("No default device was found"); } - for device in cpal::default_host().output_devices()? { + for device in host.output_devices()? { match device.name() { Ok(name) if Some(&name) == default_device_name.as_ref() => (), Ok(name) => { @@ -95,14 +114,13 @@ fn list_outputs() -> Result<(), cpal::DevicesError> { Ok(()) } -fn get_default_device() -> Option { - cpal::default_host().default_output_device() -} - -fn create_sink(device: Option) -> Result<(rodio::Sink, rodio::OutputStream), RodioError> { +fn create_sink( + host: &cpal::Host, + device: Option, +) -> Result<(rodio::Sink, rodio::OutputStream), RodioError> { let rodio_device = match device { Some(ask) if &ask == "?" => { - let exit_code = match list_outputs() { + let exit_code = match list_outputs(host) { Ok(()) => 0, Err(e) => { error!("{}", e); @@ -112,12 +130,13 @@ fn create_sink(device: Option) -> Result<(rodio::Sink, rodio::OutputStre exit(exit_code) } Some(device_name) => { - cpal::default_host() - .output_devices()? + host.output_devices()? .find(|d| d.name().ok().map_or(false, |name| name == device_name)) // Ignore devices for which getting name fails .ok_or(RodioError::DeviceNotAvailable(device_name))? } - None => get_default_device().ok_or(RodioError::NoDeviceAvailable)?, + None => host + .default_output_device() + .ok_or(RodioError::NoDeviceAvailable)?, }; let name = rodio_device.name().ok(); @@ -131,37 +150,32 @@ fn create_sink(device: Option) -> Result<(rodio::Sink, rodio::OutputStre Ok((sink, stream)) } -impl Open for RodioSink { - fn open(device: Option) -> RodioSink { - debug!( - "Using rodio sink with cpal host: {:?}", - cpal::default_host().id().name() - ); +pub fn open(host: cpal::Host, device: Option) -> RodioSink { + debug!("Using rodio sink with cpal host: {}", host.id().name()); - let (sink_tx, sink_rx) = mpsc::sync_channel(1); - let (close_tx, close_rx) = mpsc::sync_channel(1); + let (sink_tx, sink_rx) = mpsc::sync_channel(1); + let (close_tx, close_rx) = mpsc::sync_channel(1); - std::thread::spawn(move || match create_sink(device) { - Ok((sink, stream)) => { - sink_tx.send(Ok(sink)).unwrap(); + std::thread::spawn(move || match create_sink(&host, device) { + Ok((sink, stream)) => { + sink_tx.send(Ok(sink)).unwrap(); - close_rx.recv().unwrap_err(); // This will fail as soon as the sender is dropped - debug!("drop rodio::OutputStream"); - drop(stream); - } - Err(e) => { - sink_tx.send(Err(e)).unwrap(); - } - }); + close_rx.recv().unwrap_err(); // This will fail as soon as the sender is dropped + debug!("drop rodio::OutputStream"); + drop(stream); + } + Err(e) => { + sink_tx.send(Err(e)).unwrap(); + } + }); - // Instead of the second `unwrap`, better error handling could be introduced - let sink = sink_rx.recv().unwrap().unwrap(); + // Instead of the second `unwrap`, better error handling could be introduced + let sink = sink_rx.recv().unwrap().unwrap(); - debug!("Rodio sink was created"); - RodioSink { - rodio_sink: sink, - _close_tx: close_tx, - } + debug!("Rodio sink was created"); + RodioSink { + rodio_sink: sink, + _close_tx: close_tx, } } From 9253be7bc9675c266000a06fac218f444b63d66c Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Wed, 10 Feb 2021 22:40:33 +0100 Subject: [PATCH 37/75] Small refactor of librespot-core * Remove default impl for `SessionConfig` * Move util mod to single file * Restore privacy of mods * Move `fn get_credentials` to application * Remove `extern crate` statements --- Cargo.lock | 10 ---------- core/Cargo.toml | 1 - core/build.rs | 3 --- core/src/authentication.rs | 24 ---------------------- core/src/config.rs | 15 -------------- core/src/lib.rs | 30 +++------------------------- core/src/{util/mod.rs => util.rs} | 0 src/main.rs | 33 ++++++++++++++++++++++++++----- 8 files changed, 31 insertions(+), 85 deletions(-) rename core/src/{util/mod.rs => util.rs} (100%) diff --git a/Cargo.lock b/Cargo.lock index 1e8176f62..c9bcef5bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1475,7 +1475,6 @@ dependencies = [ "tokio-util", "tower-service", "url 1.7.2", - "uuid", "vergen", ] @@ -2990,15 +2989,6 @@ dependencies = [ "percent-encoding 2.1.0", ] -[[package]] -name = "uuid" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" -dependencies = [ - "getrandom 0.2.2", -] - [[package]] name = "vergen" version = "3.2.0" diff --git a/core/Cargo.toml b/core/Cargo.toml index 36d799885..673637a0d 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -40,7 +40,6 @@ tokio = { version = "1.0", features = ["io-util", "rt-multi-thread"] } tokio-util = { version = "0.6", features = ["codec"] } tower-service = "0.3" url = "1.7" -uuid = { version = "0.8", features = ["v4"] } [build-dependencies] rand = "0.7" diff --git a/core/build.rs b/core/build.rs index e8c71e4af..83f504728 100644 --- a/core/build.rs +++ b/core/build.rs @@ -1,6 +1,3 @@ -extern crate rand; -extern crate vergen; - use rand::distributions::Alphanumeric; use rand::Rng; use vergen::{generate_cargo_keys, ConstantsFlags}; diff --git a/core/src/authentication.rs b/core/src/authentication.rs index 5394ff351..fa5704098 100644 --- a/core/src/authentication.rs +++ b/core/src/authentication.rs @@ -142,30 +142,6 @@ where base64::decode(&v).map_err(|e| serde::de::Error::custom(e.to_string())) } -pub fn get_credentials String>( - username: Option, - password: Option, - cached_credentials: Option, - prompt: F, -) -> Option { - match (username, password, cached_credentials) { - (Some(username), Some(password), _) => Some(Credentials::with_password(username, password)), - - (Some(ref username), _, Some(ref credentials)) if *username == credentials.username => { - Some(credentials.clone()) - } - - (Some(username), None, _) => Some(Credentials::with_password( - username.clone(), - prompt(&username), - )), - - (None, _, Some(credentials)) => Some(credentials), - - (None, _, None) => None, - } -} - error_chain! { types { AuthenticationError, AuthenticationErrorKind, AuthenticationResultExt, AuthenticationResult; diff --git a/core/src/config.rs b/core/src/config.rs index 60cb66e0d..469b935a2 100644 --- a/core/src/config.rs +++ b/core/src/config.rs @@ -1,9 +1,6 @@ use std::fmt; use std::str::FromStr; use url::Url; -use uuid::Uuid; - -use crate::version; #[derive(Clone, Debug)] pub struct SessionConfig { @@ -13,18 +10,6 @@ pub struct SessionConfig { pub ap_port: Option, } -impl Default for SessionConfig { - fn default() -> SessionConfig { - let device_id = Uuid::new_v4().to_hyphenated().to_string(); - SessionConfig { - user_agent: version::version_string(), - device_id: device_id, - proxy: None, - ap_port: None, - } - } -} - #[derive(Clone, Copy, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)] pub enum DeviceType { Unknown = 0, diff --git a/core/src/lib.rs b/core/src/lib.rs index 25ce5413c..6c180c2ec 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -8,43 +8,19 @@ extern crate serde_derive; extern crate pin_project_lite; #[macro_use] extern crate error_chain; -extern crate aes; -extern crate base64; -extern crate byteorder; -extern crate bytes; -extern crate futures; -extern crate hmac; -extern crate httparse; -extern crate hyper; -extern crate num_bigint; -extern crate num_integer; -extern crate num_traits; -extern crate once_cell; -extern crate pbkdf2; -extern crate protobuf; -extern crate rand; -extern crate serde; -extern crate serde_json; -extern crate sha1; -extern crate shannon; -pub extern crate tokio; -extern crate tokio_util; -extern crate tower_service; -extern crate url; -extern crate uuid; -extern crate librespot_protocol as protocol; +use librespot_protocol as protocol; #[macro_use] mod component; -pub mod apresolve; +mod apresolve; pub mod audio_key; pub mod authentication; pub mod cache; pub mod channel; pub mod config; -pub mod connection; +mod connection; pub mod diffie_hellman; pub mod keymaster; pub mod mercury; diff --git a/core/src/util/mod.rs b/core/src/util.rs similarity index 100% rename from core/src/util/mod.rs rename to core/src/util.rs diff --git a/src/main.rs b/src/main.rs index 71041f55e..31ef30019 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,7 +12,7 @@ use std::{ }; use url::Url; -use librespot::core::authentication::{get_credentials, Credentials}; +use librespot::core::authentication::Credentials; use librespot::core::cache::Cache; use librespot::core::config::{ConnectConfig, DeviceType, SessionConfig, VolumeCtrl}; use librespot::core::session::Session; @@ -70,6 +70,29 @@ fn list_backends() { } } +pub fn get_credentials Option>( + username: Option, + password: Option, + cached_credentials: Option, + prompt: F, +) -> Option { + if let Some(username) = username { + if let Some(password) = password { + return Some(Credentials::with_password(username, password)); + } + + match cached_credentials { + Some(credentials) if username == credentials.username => Some(credentials), + _ => { + let password = prompt(&username)?; + Some(Credentials::with_password(username, password)) + } + } + } else { + cached_credentials + } +} + #[derive(Clone)] struct Setup { backend: fn(Option) -> Box, @@ -317,10 +340,10 @@ fn setup(args: &[String]) -> Setup { let credentials = { let cached_credentials = cache.as_ref().and_then(Cache::credentials); - let password = |username: &String| -> String { - write!(stderr(), "Password for {}: ", username).unwrap(); - stderr().flush().unwrap(); - rpassword::read_password().unwrap() + let password = |username: &String| -> Option { + write!(stderr(), "Password for {}: ", username).ok()?; + stderr().flush().ok()?; + rpassword::read_password().ok() }; get_credentials( From 8cff10e983bcf87b44de01229e2e5154a125369e Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Wed, 10 Feb 2021 22:50:08 +0100 Subject: [PATCH 38/75] Put apresolve behind feature flag --- Cargo.lock | 2 +- Cargo.toml | 5 +- core/Cargo.toml | 10 ++-- core/src/apresolve.rs | 107 ++++++++++++++++++++++------------------ core/src/lib.rs | 2 + core/src/proxytunnel.rs | 97 ++++++++++++++++++------------------ 6 files changed, 123 insertions(+), 100 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c9bcef5bb..282888ddd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1450,6 +1450,7 @@ dependencies = [ "base64", "byteorder", "bytes", + "cfg-if 1.0.0", "env_logger", "error-chain", "futures", @@ -1473,7 +1474,6 @@ dependencies = [ "shannon", "tokio", "tokio-util", - "tower-service", "url 1.7.2", "vergen", ] diff --git a/Cargo.toml b/Cargo.toml index d34189ec3..617ae0861 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,6 +61,9 @@ sha-1 = "0.8" hex = "0.4" [features] +apresolve = ["librespot-core/apresolve"] +apresolve-http2 = ["librespot-core/apresolve-http2"] + alsa-backend = ["librespot-playback/alsa-backend"] portaudio-backend = ["librespot-playback/portaudio-backend"] pulseaudio-backend = ["librespot-playback/pulseaudio-backend"] @@ -75,7 +78,7 @@ with-vorbis = ["librespot-audio/with-vorbis"] # with-dns-sd = ["librespot-connect/with-dns-sd"] -default = ["librespot-playback/rodio-backend"] +default = ["rodio-backend", "apresolve"] [package.metadata.deb] maintainer = "librespot-org" diff --git a/core/Cargo.toml b/core/Cargo.toml index 673637a0d..f1a15eb1d 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -17,11 +17,12 @@ aes = "0.6" base64 = "0.13" byteorder = "1.4" bytes = "1.0" +cfg-if = "1" error-chain = { version = "0.12", default-features = false } futures = { version = "0.3", features = ["bilock", "unstable"] } hmac = "0.10" httparse = "1.3" -hyper = { version = "0.14", features = ["client", "tcp", "http1", "http2"] } +hyper = { version = "0.14", optional = true, features = ["client", "tcp", "http1"] } log = "0.4" num-bigint = "0.3" num-integer = "0.1" @@ -38,7 +39,6 @@ sha-1 = "0.9" shannon = "0.2.0" tokio = { version = "1.0", features = ["io-util", "rt-multi-thread"] } tokio-util = { version = "0.6", features = ["codec"] } -tower-service = "0.3" url = "1.7" [build-dependencies] @@ -47,4 +47,8 @@ vergen = "3.0.4" [dev-dependencies] env_logger = "*" -tokio = {version = "1.0", features = ["macros"] } \ No newline at end of file +tokio = {version = "1.0", features = ["macros"] } + +[features] +apresolve = ["hyper"] +apresolve-http2 = ["apresolve", "hyper/http2"] diff --git a/core/src/apresolve.rs b/core/src/apresolve.rs index 81340c9d4..cd354d888 100644 --- a/core/src/apresolve.rs +++ b/core/src/apresolve.rs @@ -1,61 +1,72 @@ const AP_FALLBACK: &'static str = "ap.spotify.com:443"; -const APRESOLVE_ENDPOINT: &'static str = "http://apresolve.spotify.com:80"; -use hyper::{Body, Client, Method, Request, Uri}; -use std::error::Error; use url::Url; -use crate::proxytunnel::ProxyTunnel; +cfg_if! { + if #[cfg(feature = "apresolve")] { + const APRESOLVE_ENDPOINT: &'static str = "http://apresolve.spotify.com:80"; -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct APResolveData { - ap_list: Vec, -} + use std::error::Error; -async fn apresolve(proxy: &Option, ap_port: &Option) -> Result> { - let port = ap_port.unwrap_or(443); - - let req = Request::builder() - .method(Method::GET) - .uri( - APRESOLVE_ENDPOINT - .parse::() - .expect("invalid AP resolve URL"), - ) - .body(Body::empty())?; - - let response = if let Some(url) = proxy { - Client::builder() - .build(ProxyTunnel::new(url)?) - .request(req) - .await? - } else { - Client::new().request(req).await? - }; + use hyper::{Body, Client, Method, Request, Uri}; + + use crate::proxytunnel::ProxyTunnel; + + #[derive(Clone, Debug, Serialize, Deserialize)] + pub struct APResolveData { + ap_list: Vec, + } - let body = hyper::body::to_bytes(response.into_body()).await?; - let data: APResolveData = serde_json::from_slice(body.as_ref())?; + async fn apresolve(proxy: &Option, ap_port: &Option) -> Result> { + let port = ap_port.unwrap_or(443); - let ap = if ap_port.is_some() || proxy.is_some() { - data.ap_list.into_iter().find_map(|ap| { - if ap.parse::().ok()?.port()? == port { - Some(ap) + let req = Request::builder() + .method(Method::GET) + .uri( + APRESOLVE_ENDPOINT + .parse::() + .expect("invalid AP resolve URL"), + ) + .body(Body::empty())?; + + let response = if let Some(url) = proxy { + Client::builder() + .build(ProxyTunnel::new(url)?) + .request(req) + .await? } else { - None + Client::new().request(req).await? + }; + + let body = hyper::body::to_bytes(response.into_body()).await?; + let data: APResolveData = serde_json::from_slice(body.as_ref())?; + + let ap = if ap_port.is_some() || proxy.is_some() { + data.ap_list.into_iter().find_map(|ap| { + if ap.parse::().ok()?.port()? == port { + Some(ap) + } else { + None + } + }) + } else { + data.ap_list.into_iter().next() } - }) - } else { - data.ap_list.into_iter().next() - } - .ok_or("empty AP List")?; + .ok_or("empty AP List")?; - Ok(ap) -} + Ok(ap) + } -pub async fn apresolve_or_fallback(proxy: &Option, ap_port: &Option) -> String { - apresolve(proxy, ap_port).await.unwrap_or_else(|e| { - warn!("Failed to resolve Access Point: {}", e); - warn!("Using fallback \"{}\"", AP_FALLBACK); - AP_FALLBACK.into() - }) + pub async fn apresolve_or_fallback(proxy: &Option, ap_port: &Option) -> String { + apresolve(proxy, ap_port).await.unwrap_or_else(|e| { + warn!("Failed to resolve Access Point: {}", e); + warn!("Using fallback \"{}\"", AP_FALLBACK); + AP_FALLBACK.into() + }) + } + } else { + pub async fn apresolve_or_fallback(_: &Option, _: &Option) -> String { + AP_FALLBACK.to_string() + } + } } diff --git a/core/src/lib.rs b/core/src/lib.rs index 6c180c2ec..65fa898aa 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -3,6 +3,8 @@ #[macro_use] extern crate log; #[macro_use] +extern crate cfg_if; +#[macro_use] extern crate serde_derive; #[macro_use] extern crate pin_project_lite; diff --git a/core/src/proxytunnel.rs b/core/src/proxytunnel.rs index c2033c851..158d314f6 100644 --- a/core/src/proxytunnel.rs +++ b/core/src/proxytunnel.rs @@ -1,16 +1,6 @@ -use futures::Future; -use hyper::Uri; -use std::{ - io, - net::{SocketAddr, ToSocketAddrs}, - pin::Pin, - task::Poll, -}; -use tokio::{ - io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}, - net::TcpStream, -}; -use tower_service::Service; +use std::io; + +use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; pub async fn connect( mut proxy_connection: T, @@ -64,43 +54,56 @@ pub async fn connect( } } -#[derive(Clone)] -pub struct ProxyTunnel { - proxy_addr: SocketAddr, -} +cfg_if! { + if #[cfg(feature = "apresolve")] { + use std::future::Future; + use std::net::{SocketAddr, ToSocketAddrs}; + use std::pin::Pin; + use std::task::Poll; -impl ProxyTunnel { - pub fn new(addr: T) -> io::Result { - let addr = addr.to_socket_addrs()?.next().ok_or_else(|| { - io::Error::new(io::ErrorKind::InvalidInput, "No socket address given") - })?; - Ok(Self { proxy_addr: addr }) - } -} + use hyper::service::Service; + use hyper::Uri; + use tokio::net::TcpStream; -impl Service for ProxyTunnel { - type Response = TcpStream; - type Error = io::Error; - type Future = Pin> + Send>>; + #[derive(Clone)] + pub struct ProxyTunnel { + proxy_addr: SocketAddr, + } - fn poll_ready(&mut self, _: &mut std::task::Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } + impl ProxyTunnel { + pub fn new(addr: T) -> io::Result { + let addr = addr.to_socket_addrs()?.next().ok_or_else(|| { + io::Error::new(io::ErrorKind::InvalidInput, "No socket address given") + })?; + Ok(Self { proxy_addr: addr }) + } + } + + impl Service for ProxyTunnel { + type Response = TcpStream; + type Error = io::Error; + type Future = Pin> + Send>>; + + fn poll_ready(&mut self, _: &mut std::task::Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } - fn call(&mut self, url: Uri) -> Self::Future { - let proxy_addr = self.proxy_addr; - let fut = async move { - let host = url - .host() - .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Host is missing"))?; - let port = url - .port() - .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Port is missing"))?; - - let conn = TcpStream::connect(proxy_addr).await?; - connect(conn, host, port.as_u16()).await - }; - - Box::pin(fut) + fn call(&mut self, url: Uri) -> Self::Future { + let proxy_addr = self.proxy_addr; + let fut = async move { + let host = url + .host() + .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Host is missing"))?; + let port = url + .port() + .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Port is missing"))?; + + let conn = TcpStream::connect(proxy_addr).await?; + connect(conn, host, port.as_u16()).await + }; + + Box::pin(fut) + } + } } } From 10827bd6a8a2a098b35b5d6ad766ef34d460d3b6 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Wed, 10 Feb 2021 22:54:35 +0100 Subject: [PATCH 39/75] Clean up dependencies of librespot-core * Use sub-crates of future * Remove unnecessary pin-project * Removed unused crates and features * Replace futures channels by tokio channels * Use serde's "derive" feature flag instead of serde_derive --- Cargo.lock | 20 ++++++++++++++++---- core/Cargo.toml | 17 +++++++++-------- core/build.rs | 6 +++--- core/src/apresolve.rs | 1 + core/src/audio_key.rs | 2 +- core/src/authentication.rs | 5 ++++- core/src/channel.rs | 22 ++++++++++++---------- core/src/connection/mod.rs | 2 +- core/src/keymaster.rs | 2 ++ core/src/lib.rs | 4 ---- core/src/mercury/mod.rs | 34 +++++++++++++++++----------------- core/src/session.rs | 23 +++++++++++++++-------- 12 files changed, 81 insertions(+), 57 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 282888ddd..7fe8387d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1453,7 +1453,9 @@ dependencies = [ "cfg-if 1.0.0", "env_logger", "error-chain", - "futures", + "futures-core", + "futures-sink", + "futures-util", "hmac", "httparse", "hyper", @@ -1464,15 +1466,14 @@ dependencies = [ "num-traits", "once_cell", "pbkdf2", - "pin-project-lite", "protobuf", - "rand 0.7.3", + "rand 0.8.3", "serde", - "serde_derive", "serde_json", "sha-1 0.9.4", "shannon", "tokio", + "tokio-stream", "tokio-util", "url 1.7.2", "vergen", @@ -2819,6 +2820,17 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-stream" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1981ad97df782ab506a1f43bf82c967326960d278acf3bf8279809648c3ff3ea" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + [[package]] name = "tokio-util" version = "0.6.3" diff --git a/core/Cargo.toml b/core/Cargo.toml index f1a15eb1d..85f3be621 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -19,7 +19,9 @@ byteorder = "1.4" bytes = "1.0" cfg-if = "1" error-chain = { version = "0.12", default-features = false } -futures = { version = "0.3", features = ["bilock", "unstable"] } +futures-core = { version = "0.3", default-features = false } +futures-sink = { version = "0.3", default-features = false } +futures-util = { version = "0.3", default-features = false, features = ["alloc", "bilock", "unstable", "sink"] } hmac = "0.10" httparse = "1.3" hyper = { version = "0.14", optional = true, features = ["client", "tcp", "http1"] } @@ -28,21 +30,20 @@ num-bigint = "0.3" num-integer = "0.1" num-traits = "0.2" once_cell = "1.5.2" -pbkdf2 = { version = "0.7", default_features = false, features = ["hmac"] } -pin-project-lite = "0.2.4" +pbkdf2 = { version = "0.7", default-features = false, features = ["hmac"] } protobuf = "~2.14.0" -rand = "0.7" -serde = "1.0" -serde_derive = "1.0" +rand = "0.8" +serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" sha-1 = "0.9" shannon = "0.2.0" -tokio = { version = "1.0", features = ["io-util", "rt-multi-thread"] } +tokio = { version = "1.0", features = ["io-util", "net", "rt", "sync"] } +tokio-stream = "0.1" tokio-util = { version = "0.6", features = ["codec"] } url = "1.7" [build-dependencies] -rand = "0.7" +rand = "0.8" vergen = "3.0.4" [dev-dependencies] diff --git a/core/build.rs b/core/build.rs index 83f504728..0fc293354 100644 --- a/core/build.rs +++ b/core/build.rs @@ -7,10 +7,10 @@ fn main() { flags.toggle(ConstantsFlags::REBUILD_ON_HEAD_CHANGE); generate_cargo_keys(ConstantsFlags::all()).expect("Unable to generate the cargo keys!"); - let mut rng = rand::thread_rng(); - let build_id: String = ::std::iter::repeat(()) - .map(|()| rng.sample(Alphanumeric)) + let build_id: String = rand::thread_rng() + .sample_iter(Alphanumeric) .take(8) + .map(char::from) .collect(); println!("cargo:rustc-env=VERGEN_BUILD_ID={}", build_id); } diff --git a/core/src/apresolve.rs b/core/src/apresolve.rs index cd354d888..7698691c9 100644 --- a/core/src/apresolve.rs +++ b/core/src/apresolve.rs @@ -9,6 +9,7 @@ cfg_if! { use std::error::Error; use hyper::{Body, Client, Method, Request, Uri}; + use serde::{Serialize, Deserialize}; use crate::proxytunnel::ProxyTunnel; diff --git a/core/src/audio_key.rs b/core/src/audio_key.rs index b9f0c2328..3bce1c73e 100644 --- a/core/src/audio_key.rs +++ b/core/src/audio_key.rs @@ -1,8 +1,8 @@ use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; use bytes::Bytes; -use futures::channel::oneshot; use std::collections::HashMap; use std::io::Write; +use tokio::sync::oneshot; use crate::spotify_id::{FileId, SpotifyId}; use crate::util::SeqGenerator; diff --git a/core/src/authentication.rs b/core/src/authentication.rs index fa5704098..ff477df56 100644 --- a/core/src/authentication.rs +++ b/core/src/authentication.rs @@ -1,10 +1,13 @@ +use std::io::{self, Read}; +use std::ops::FnOnce; + use aes::Aes192; use byteorder::{BigEndian, ByteOrder}; use hmac::Hmac; use pbkdf2::pbkdf2; use protobuf::ProtobufEnum; +use serde::{Deserialize, Serialize}; use sha1::{Digest, Sha1}; -use std::io::{self, Read}; use crate::protocol::authentication::AuthenticationType; use crate::protocol::keyexchange::{APLoginFailed, ErrorCode}; diff --git a/core/src/channel.rs b/core/src/channel.rs index 7ada05d5e..54eee1841 100644 --- a/core/src/channel.rs +++ b/core/src/channel.rs @@ -1,12 +1,14 @@ +use std::collections::HashMap; +use std::pin::Pin; +use std::task::{Context, Poll}; +use std::time::Instant; + use byteorder::{BigEndian, ByteOrder}; use bytes::Bytes; -use futures::{channel::mpsc, lock::BiLock, Stream, StreamExt}; -use std::{ - collections::HashMap, - pin::Pin, - task::{Context, Poll}, - time::Instant, -}; +use futures_core::Stream; +use futures_util::lock::BiLock; +use futures_util::StreamExt; +use tokio::sync::mpsc; use crate::util::SeqGenerator; @@ -46,7 +48,7 @@ enum ChannelState { impl ChannelManager { pub fn allocate(&self) -> (u16, Channel) { - let (tx, rx) = mpsc::unbounded(); + let (tx, rx) = mpsc::unbounded_channel(); let seq = self.lock(|inner| { let seq = inner.sequence.get(); @@ -85,7 +87,7 @@ impl ChannelManager { inner.download_measurement_bytes += data.len(); if let Entry::Occupied(entry) = inner.channels.entry(id) { - let _ = entry.get().unbounded_send((cmd, data)); + let _ = entry.get().send((cmd, data)); } }); } @@ -105,7 +107,7 @@ impl ChannelManager { impl Channel { fn recv_packet(&mut self, cx: &mut Context<'_>) -> Poll> { - let (cmd, packet) = match self.receiver.poll_next_unpin(cx) { + let (cmd, packet) = match self.receiver.poll_recv(cx) { Poll::Pending => return Poll::Pending, Poll::Ready(o) => o.ok_or(ChannelError)?, }; diff --git a/core/src/connection/mod.rs b/core/src/connection/mod.rs index 68e2e7a50..6bdbde6a8 100644 --- a/core/src/connection/mod.rs +++ b/core/src/connection/mod.rs @@ -4,7 +4,7 @@ mod handshake; pub use self::codec::APCodec; pub use self::handshake::handshake; -use futures::{SinkExt, StreamExt}; +use futures_util::{SinkExt, StreamExt}; use protobuf::{self, Message}; use std::io; use std::net::ToSocketAddrs; diff --git a/core/src/keymaster.rs b/core/src/keymaster.rs index 87b3f1e30..8c3c00a21 100644 --- a/core/src/keymaster.rs +++ b/core/src/keymaster.rs @@ -1,3 +1,5 @@ +use serde::Deserialize; + use crate::{mercury::MercuryError, session::Session}; #[derive(Deserialize, Debug, Clone)] diff --git a/core/src/lib.rs b/core/src/lib.rs index 65fa898aa..54f83f17e 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -5,10 +5,6 @@ extern crate log; #[macro_use] extern crate cfg_if; #[macro_use] -extern crate serde_derive; -#[macro_use] -extern crate pin_project_lite; -#[macro_use] extern crate error_chain; use librespot_protocol as protocol; diff --git a/core/src/mercury/mod.rs b/core/src/mercury/mod.rs index 4baa674f3..537ff2cb8 100644 --- a/core/src/mercury/mod.rs +++ b/core/src/mercury/mod.rs @@ -1,14 +1,17 @@ +use std::collections::HashMap; +use std::future::Future; +use std::mem; +use std::pin::Pin; +use std::task::Context; +use std::task::Poll; + +use byteorder::{BigEndian, ByteOrder}; +use bytes::Bytes; +use tokio::sync::{mpsc, oneshot}; + use crate::protocol; use crate::util::url_encode; use crate::util::SeqGenerator; -use byteorder::{BigEndian, ByteOrder}; -use bytes::Bytes; -use futures::{ - channel::{mpsc, oneshot}, - Future, -}; -use std::{collections::HashMap, task::Poll}; -use std::{mem, pin::Pin, task::Context}; mod types; pub use self::types::*; @@ -31,18 +34,15 @@ pub struct MercuryPending { callback: Option>>, } -pin_project! { - pub struct MercuryFuture { - #[pin] - receiver: oneshot::Receiver> - } +pub struct MercuryFuture { + receiver: oneshot::Receiver>, } impl Future for MercuryFuture { type Output = Result; - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - match self.project().receiver.poll(cx) { + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + match Pin::new(&mut self.receiver).poll(cx) { Poll::Ready(Ok(x)) => Poll::Ready(x), Poll::Ready(Err(_)) => Poll::Ready(Err(MercuryError)), Poll::Pending => Poll::Pending, @@ -119,7 +119,7 @@ impl MercuryManager { async move { let response = request.await?; - let (tx, rx) = mpsc::unbounded(); + let (tx, rx) = mpsc::unbounded_channel(); manager.lock(move |inner| { if !inner.invalid { @@ -221,7 +221,7 @@ impl MercuryManager { // if send fails, remove from list of subs // TODO: send unsub message - sub.unbounded_send(response.clone()).is_ok() + sub.send(response.clone()).is_ok() } else { // URI doesn't match true diff --git a/core/src/session.rs b/core/src/session.rs index b0eca0c00..858a0b696 100644 --- a/core/src/session.rs +++ b/core/src/session.rs @@ -1,14 +1,19 @@ +use std::future::Future; +use std::io; +use std::pin::Pin; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, RwLock, Weak}; +use std::task::Context; use std::task::Poll; use std::time::{SystemTime, UNIX_EPOCH}; -use std::{io, pin::Pin, task::Context}; - -use once_cell::sync::OnceCell; use byteorder::{BigEndian, ByteOrder}; use bytes::Bytes; -use futures::{channel::mpsc, Future, FutureExt, StreamExt, TryStream, TryStreamExt}; +use futures_core::TryStream; +use futures_util::{FutureExt, StreamExt, TryStreamExt}; +use once_cell::sync::OnceCell; +use tokio::sync::mpsc; +use tokio_stream::wrappers::UnboundedReceiverStream; use crate::apresolve::apresolve_or_fallback; use crate::audio_key::AudioKeyManager; @@ -87,7 +92,7 @@ impl Session { ) -> Session { let (sink, stream) = transport.split(); - let (sender_tx, sender_rx) = mpsc::unbounded(); + let (sender_tx, sender_rx) = mpsc::unbounded_channel(); let session_id = SESSION_COUNTER.fetch_add(1, Ordering::Relaxed); debug!("new Session[{}]", session_id); @@ -114,11 +119,13 @@ impl Session { session_id: session_id, })); - let sender_task = sender_rx.map(Ok::<_, io::Error>).forward(sink); + let sender_task = UnboundedReceiverStream::new(sender_rx) + .map(Ok) + .forward(sink); let receiver_task = DispatchTask(stream, session.weak()); let task = - futures::future::join(sender_task, receiver_task).map(|_| io::Result::<_>::Ok(())); + futures_util::future::join(sender_task, receiver_task).map(|_| io::Result::<_>::Ok(())); tokio::spawn(task); session } @@ -193,7 +200,7 @@ impl Session { } pub fn send_packet(&self, cmd: u8, data: Vec) { - self.0.tx_connection.unbounded_send((cmd, data)).unwrap(); + self.0.tx_connection.send((cmd, data)).unwrap(); } pub fn cache(&self) -> Option<&Arc> { From a6ed6857d25e0eff8fd16bf14d17f5e2be6bf644 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Wed, 10 Feb 2021 23:03:33 +0100 Subject: [PATCH 40/75] Clean up dependencies in librespot-metadata * Replaced LinearMap by HashMap * Removed unnecessary dependencies * Removed "extern crate"s --- Cargo.lock | 8 -------- metadata/Cargo.toml | 2 -- metadata/src/lib.rs | 18 ++++++------------ 3 files changed, 6 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7fe8387d0..94aea40b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1485,10 +1485,8 @@ version = "0.1.6" dependencies = [ "async-trait", "byteorder", - "futures", "librespot-core", "librespot-protocol", - "linear-map", "log", "protobuf", ] @@ -1542,12 +1540,6 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "linear-map" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfae20f6b19ad527b550c223fddc3077a547fc70cda94b9b566575423fd303ee" - [[package]] name = "lock_api" version = "0.4.2" diff --git a/metadata/Cargo.toml b/metadata/Cargo.toml index 6baae5d90..f3087b8a9 100644 --- a/metadata/Cargo.toml +++ b/metadata/Cargo.toml @@ -10,8 +10,6 @@ edition = "2018" [dependencies] async-trait = "0.1" byteorder = "1.3" -futures = "0.3" -linear-map = "1.2" protobuf = "~2.14.0" log = "0.4" diff --git a/metadata/src/lib.rs b/metadata/src/lib.rs index f71bae95d..8faa027e1 100644 --- a/metadata/src/lib.rs +++ b/metadata/src/lib.rs @@ -1,26 +1,20 @@ #![allow(clippy::unused_io_amount)] #![allow(clippy::redundant_field_names)] + #[macro_use] extern crate log; #[macro_use] extern crate async_trait; -extern crate byteorder; -extern crate futures; -extern crate linear_map; -extern crate protobuf; - -extern crate librespot_core; -extern crate librespot_protocol as protocol; - pub mod cover; -use linear_map::LinearMap; +use std::collections::HashMap; use librespot_core::mercury::MercuryError; use librespot_core::session::Session; use librespot_core::spotify_id::{FileId, SpotifyAudioType, SpotifyId}; +use librespot_protocol as protocol; pub use crate::protocol::metadata::AudioFile_Format as FileFormat; @@ -64,7 +58,7 @@ where pub struct AudioItem { pub id: SpotifyId, pub uri: String, - pub files: LinearMap, + pub files: HashMap, pub name: String, pub duration: i32, pub available: bool, @@ -143,7 +137,7 @@ pub struct Track { pub duration: i32, pub album: SpotifyId, pub artists: Vec, - pub files: LinearMap, + pub files: HashMap, pub alternatives: Vec, pub available: bool, } @@ -165,7 +159,7 @@ pub struct Episode { pub duration: i32, pub language: String, pub show: SpotifyId, - pub files: LinearMap, + pub files: HashMap, pub covers: Vec, pub available: bool, pub explicit: bool, From 746e6c863eeb58a0dc55ed468edac3d8e85823f7 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Wed, 10 Feb 2021 23:07:59 +0100 Subject: [PATCH 41/75] Put lewton behind feature flag --- Cargo.lock | 1 + Cargo.toml | 3 ++- audio/Cargo.toml | 6 ++++-- audio/src/lib.rs | 32 ++++++++++++++++++++++---------- 4 files changed, 29 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 94aea40b2..55bc1f7e4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1402,6 +1402,7 @@ dependencies = [ "bit-set", "byteorder", "bytes", + "cfg-if 1.0.0", "futures", "lewton", "librespot-core", diff --git a/Cargo.toml b/Cargo.toml index 617ae0861..a26db2ed6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -75,10 +75,11 @@ gstreamer-backend = ["librespot-playback/gstreamer-backend"] with-tremor = ["librespot-audio/with-tremor"] with-vorbis = ["librespot-audio/with-vorbis"] +with-lewton = ["librespot-audio/with-lewton"] # with-dns-sd = ["librespot-connect/with-dns-sd"] -default = ["rodio-backend", "apresolve"] +default = ["rodio-backend", "apresolve", "with-lewton"] [package.metadata.deb] maintainer = "librespot-org" diff --git a/audio/Cargo.toml b/audio/Cargo.toml index 96af08f2b..01d81f044 100644 --- a/audio/Cargo.toml +++ b/audio/Cargo.toml @@ -15,18 +15,20 @@ aes-ctr = "0.6" bit-set = "0.5" byteorder = "1.4" bytes = "1.0" +cfg-if = "1" futures = "0.3" -lewton = "0.10" -ogg = "0.8" log = "0.4" num-bigint = "0.3" num-traits = "0.2" +ogg = "0.8" pin-project-lite = "0.2.4" tempfile = "3.1" +lewton = { version = "0.10", optional = true } librespot-tremor = { version = "0.2.0", optional = true } vorbis = { version ="0.0.14", optional = true } [features] +with-lewton = ["lewton"] with-tremor = ["librespot-tremor"] with-vorbis = ["vorbis"] diff --git a/audio/src/lib.rs b/audio/src/lib.rs index 3f22ac5d1..8b3a8dfa2 100644 --- a/audio/src/lib.rs +++ b/audio/src/lib.rs @@ -19,11 +19,29 @@ extern crate librespot_core; mod decrypt; mod fetch; -#[cfg(not(any(feature = "with-tremor", feature = "with-vorbis")))] -mod lewton_decoder; -#[cfg(any(feature = "with-tremor", feature = "with-vorbis"))] -mod libvorbis_decoder; +use cfg_if::cfg_if; + +#[cfg(any( + all(feature = "with-lewton", feature = "with-tremor"), + all(feature = "with-vorbis", feature = "with-tremor"), + all(feature = "with-lewton", feature = "with-vorbis") +))] +compile_error!("Cannot use two decoders at the same time."); + +cfg_if! { + if #[cfg(feature = "with-lewton")] { + mod lewton_decoder; + pub use lewton_decoder::{VorbisDecoder, VorbisError}; + } else if #[cfg(any(feature = "with-tremor", feature = "with-vorbis"))] { + mod libvorbis_decoder; + pub use crate::libvorbis_decoder::{VorbisDecoder, VorbisError}; + } else { + compile_error!("Must choose a vorbis decoder."); + } +} + mod passthrough_decoder; +pub use passthrough_decoder::{PassthroughDecoder, PassthroughError}; mod range_set; @@ -63,12 +81,6 @@ impl AudioPacket { } } -#[cfg(not(any(feature = "with-tremor", feature = "with-vorbis")))] -pub use crate::lewton_decoder::{VorbisDecoder, VorbisError}; -#[cfg(any(feature = "with-tremor", feature = "with-vorbis"))] -pub use libvorbis_decoder::{VorbisDecoder, VorbisError}; -pub use passthrough_decoder::{PassthroughDecoder, PassthroughError}; - #[derive(Debug)] pub enum AudioError { PassthroughError(PassthroughError), From b83976a8ec29f7b34ddcdadb02254dd8f90f7e2a Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Wed, 10 Feb 2021 23:13:32 +0100 Subject: [PATCH 42/75] Remove "extern crate"s from librespot-audio --- audio/src/lewton_decoder.rs | 12 +++++------- audio/src/lib.rs | 11 ----------- audio/src/libvorbis_decoder.rs | 4 +--- 3 files changed, 6 insertions(+), 21 deletions(-) diff --git a/audio/src/lewton_decoder.rs b/audio/src/lewton_decoder.rs index 1addaa011..086ea57e0 100644 --- a/audio/src/lewton_decoder.rs +++ b/audio/src/lewton_decoder.rs @@ -1,6 +1,4 @@ -extern crate lewton; - -use self::lewton::inside_ogg::OggStreamReader; +use lewton::inside_ogg::OggStreamReader; use super::{AudioDecoder, AudioError, AudioPacket}; use std::error; @@ -32,10 +30,10 @@ where } fn next_packet(&mut self) -> Result, AudioError> { - use self::lewton::audio::AudioReadError::AudioIsHeader; - use self::lewton::OggReadError::NoCapturePatternFound; - use self::lewton::VorbisError::BadAudio; - use self::lewton::VorbisError::OggError; + use lewton::audio::AudioReadError::AudioIsHeader; + use lewton::OggReadError::NoCapturePatternFound; + use lewton::VorbisError::BadAudio; + use lewton::VorbisError::OggError; loop { match self.0.read_dec_packet_itl() { Ok(Some(packet)) => return Ok(Some(AudioPacket::Samples(packet))), diff --git a/audio/src/lib.rs b/audio/src/lib.rs index 8b3a8dfa2..9bb6f8e44 100644 --- a/audio/src/lib.rs +++ b/audio/src/lib.rs @@ -5,17 +5,6 @@ extern crate log; #[macro_use] extern crate pin_project_lite; -extern crate aes_ctr; -extern crate bit_set; -extern crate byteorder; -extern crate bytes; -extern crate futures; -extern crate num_bigint; -extern crate num_traits; -extern crate tempfile; - -extern crate librespot_core; - mod decrypt; mod fetch; diff --git a/audio/src/libvorbis_decoder.rs b/audio/src/libvorbis_decoder.rs index 8aced5562..eeef8ab9e 100644 --- a/audio/src/libvorbis_decoder.rs +++ b/audio/src/libvorbis_decoder.rs @@ -1,7 +1,5 @@ #[cfg(feature = "with-tremor")] -extern crate librespot_tremor as vorbis; -#[cfg(not(feature = "with-tremor"))] -extern crate vorbis; +use librespot_tremor as vorbis; use super::{AudioDecoder, AudioError, AudioPacket}; use std::error; From 5c42d2e879ae7b72c710a68ff992dfd792477d65 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Wed, 10 Feb 2021 23:18:13 +0100 Subject: [PATCH 43/75] Clean up dependencies in librespot-audio * Remove unused deps * Use futures-util instead of futures * Replace futures channels by tokio channels * Remove unnecessary pin_project * Reordered "use" statements --- Cargo.lock | 22 ++----------- audio/Cargo.toml | 7 ++-- audio/src/fetch.rs | 72 ++++++++++++++++++------------------------ audio/src/lib.rs | 2 -- audio/src/range_set.rs | 2 +- 5 files changed, 36 insertions(+), 69 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 55bc1f7e4..a8577d19d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -180,21 +180,6 @@ dependencies = [ "shlex", ] -[[package]] -name = "bit-set" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - [[package]] name = "bitflags" version = "1.2.1" @@ -1399,20 +1384,17 @@ name = "librespot-audio" version = "0.1.6" dependencies = [ "aes-ctr", - "bit-set", "byteorder", "bytes", "cfg-if 1.0.0", - "futures", + "futures-util", "lewton", "librespot-core", "librespot-tremor", "log", - "num-bigint", - "num-traits", "ogg", - "pin-project-lite", "tempfile", + "tokio", "vorbis", ] diff --git a/audio/Cargo.toml b/audio/Cargo.toml index 01d81f044..d8c0eea28 100644 --- a/audio/Cargo.toml +++ b/audio/Cargo.toml @@ -12,17 +12,14 @@ version = "0.1.6" [dependencies] aes-ctr = "0.6" -bit-set = "0.5" byteorder = "1.4" bytes = "1.0" cfg-if = "1" -futures = "0.3" log = "0.4" -num-bigint = "0.3" -num-traits = "0.2" +futures-util = { version = "0.3", default_features = false } ogg = "0.8" -pin-project-lite = "0.2.4" tempfile = "3.1" +tokio = { version = "1", features = ["sync"] } lewton = { version = "0.10", optional = true } librespot-tremor = { version = "0.2.0", optional = true } diff --git a/audio/src/fetch.rs b/audio/src/fetch.rs index 286a2b882..0ec9b01df 100644 --- a/audio/src/fetch.rs +++ b/audio/src/fetch.rs @@ -1,30 +1,23 @@ -use crate::range_set::{Range, RangeSet}; -use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; -use bytes::Bytes; -use futures::{ - channel::{mpsc, oneshot}, - future, -}; -use futures::{Future, Stream, StreamExt, TryFutureExt, TryStreamExt}; - +use std::cmp::{max, min}; use std::fs; +use std::future::Future; use std::io::{self, Read, Seek, SeekFrom, Write}; +use std::pin::Pin; +use std::sync::atomic::{self, AtomicUsize}; use std::sync::{Arc, Condvar, Mutex}; -use std::task::Poll; +use std::task::{Context, Poll}; use std::time::{Duration, Instant}; -use std::{ - cmp::{max, min}, - pin::Pin, - task::Context, -}; -use tempfile::NamedTempFile; -use futures::channel::mpsc::unbounded; +use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; +use bytes::Bytes; +use futures_util::{future, StreamExt, TryFutureExt, TryStreamExt}; use librespot_core::channel::{Channel, ChannelData, ChannelError, ChannelHeaders}; use librespot_core::session::Session; use librespot_core::spotify_id::FileId; -use std::sync::atomic; -use std::sync::atomic::AtomicUsize; +use tempfile::NamedTempFile; +use tokio::sync::{mpsc, oneshot}; + +use crate::range_set::{Range, RangeSet}; const MINIMUM_DOWNLOAD_SIZE: usize = 1024 * 16; // The minimum size of a block that is requested from the Spotify servers in one request. @@ -96,6 +89,7 @@ pub enum AudioFile { Streaming(AudioFileStreaming), } +#[derive(Debug)] enum StreamLoaderCommand { Fetch(Range), // signal the stream loader to fetch a range of the file RandomAccessMode(), // optimise download strategy for random access @@ -147,7 +141,7 @@ impl StreamLoaderController { fn send_stream_loader_command(&mut self, command: StreamLoaderCommand) { if let Some(ref mut channel) = self.channel_tx { // ignore the error in case the channel has been closed already. - let _ = channel.unbounded_send(command); + let _ = channel.send(command); } } @@ -191,7 +185,7 @@ impl StreamLoaderController { // We can't use self.fetch here because self can't be borrowed mutably, so we access the channel directly. if let Some(ref mut channel) = self.channel_tx { // ignore the error in case the channel has been closed already. - let _ = channel.unbounded_send(StreamLoaderCommand::Fetch(range)); + let _ = channel.send(StreamLoaderCommand::Fetch(range)); } } } @@ -387,7 +381,7 @@ impl AudioFileStreaming { //let (seek_tx, seek_rx) = mpsc::unbounded(); let (stream_loader_command_tx, stream_loader_command_rx) = - mpsc::unbounded::(); + mpsc::unbounded_channel::(); let fetcher = AudioFileFetch::new( session.clone(), @@ -490,12 +484,12 @@ async fn audio_file_fetch_receive_data( duration_ms = duration.as_millis() as u64; } let _ = file_data_tx - .unbounded_send(ReceivedData::ResponseTimeMs(duration_ms as usize)); + .send(ReceivedData::ResponseTimeMs(duration_ms as usize)); measure_ping_time = false; } let data_size = data.len(); let _ = file_data_tx - .unbounded_send(ReceivedData::Data(PartialFileData { + .send(ReceivedData::Data(PartialFileData { offset: data_offset, data: data, })); @@ -696,21 +690,17 @@ async fn audio_file_fetch( future::select_all(vec![f1, f2, f3]).await }*/ -pin_project! { - struct AudioFileFetch { - session: Session, - shared: Arc, - output: Option, +struct AudioFileFetch { + session: Session, + shared: Arc, + output: Option, - file_data_tx: mpsc::UnboundedSender, - #[pin] - file_data_rx: mpsc::UnboundedReceiver, + file_data_tx: mpsc::UnboundedSender, + file_data_rx: mpsc::UnboundedReceiver, - #[pin] - stream_loader_command_rx: mpsc::UnboundedReceiver, - complete_tx: Option>, - network_response_times_ms: Vec, - } + stream_loader_command_rx: mpsc::UnboundedReceiver, + complete_tx: Option>, + network_response_times_ms: Vec, } impl AudioFileFetch { @@ -725,7 +715,7 @@ impl AudioFileFetch { stream_loader_command_rx: mpsc::UnboundedReceiver, complete_tx: oneshot::Sender, ) -> AudioFileFetch { - let (file_data_tx, file_data_rx) = unbounded::(); + let (file_data_tx, file_data_rx) = mpsc::unbounded_channel::(); { let requested_range = Range::new(0, initial_data_length); @@ -863,7 +853,7 @@ impl AudioFileFetch { fn poll_file_data_rx(&mut self, cx: &mut Context<'_>) -> Poll<()> { loop { - match Pin::new(&mut self.file_data_rx).poll_next(cx) { + match self.file_data_rx.poll_recv(cx) { Poll::Ready(None) => return Poll::Ready(()), Poll::Ready(Some(ReceivedData::ResponseTimeMs(response_time_ms))) => { trace!("Ping time estimated as: {} ms.", response_time_ms); @@ -939,7 +929,7 @@ impl AudioFileFetch { fn poll_stream_loader_command_rx(&mut self, cx: &mut Context<'_>) -> Poll<()> { loop { - match Pin::new(&mut self.stream_loader_command_rx).poll_next(cx) { + match self.stream_loader_command_rx.poll_recv(cx) { Poll::Ready(None) => return Poll::Ready(()), Poll::Ready(Some(cmd)) => match cmd { StreamLoaderCommand::Fetch(request) => { @@ -1059,7 +1049,7 @@ impl Read for AudioFileStreaming { for &range in ranges_to_request.iter() { self.stream_loader_command_tx - .unbounded_send(StreamLoaderCommand::Fetch(range)) + .send(StreamLoaderCommand::Fetch(range)) .unwrap(); } diff --git a/audio/src/lib.rs b/audio/src/lib.rs index 9bb6f8e44..099fb4a82 100644 --- a/audio/src/lib.rs +++ b/audio/src/lib.rs @@ -2,8 +2,6 @@ #[macro_use] extern crate log; -#[macro_use] -extern crate pin_project_lite; mod decrypt; mod fetch; diff --git a/audio/src/range_set.rs b/audio/src/range_set.rs index d01d888e7..31ce6500e 100644 --- a/audio/src/range_set.rs +++ b/audio/src/range_set.rs @@ -2,7 +2,7 @@ use std::cmp::{max, min}; use std::fmt; use std::slice::Iter; -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct Range { pub start: usize, pub length: usize, From 5aeb733ad973537e7855a144abf0c64bad54c7e5 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Mon, 22 Feb 2021 09:55:40 +0100 Subject: [PATCH 44/75] Clean up dependencies in librespot-playback * Use futures-util instead of futures * Use tokio channels instead of futures channels * Removed "extern crate"s --- Cargo.lock | 4 +++- playback/Cargo.toml | 4 +++- playback/src/lib.rs | 36 +++------------------------- playback/src/player.rs | 53 +++++++++++++++++++++--------------------- 4 files changed, 36 insertions(+), 61 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a8577d19d..1d6871126 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1481,7 +1481,8 @@ dependencies = [ "alsa", "byteorder", "cpal", - "futures", + "futures-executor", + "futures-util", "glib", "gstreamer", "gstreamer-app", @@ -1498,6 +1499,7 @@ dependencies = [ "sdl2", "shell-words", "thiserror", + "tokio", "zerocopy", ] diff --git a/playback/Cargo.toml b/playback/Cargo.toml index 2759ae0e4..e32ee7ba2 100644 --- a/playback/Cargo.toml +++ b/playback/Cargo.toml @@ -18,10 +18,12 @@ path = "../metadata" version = "0.1.6" [dependencies] -futures = "0.3" +futures-executor = { version = "0.3", default_features = false } +futures-util = { version = "0.3", default_features = false } log = "0.4" byteorder = "1.4" shell-words = "1.0.0" +tokio = { version = "1", features = ["sync"] } alsa = { version = "0.4", optional = true } portaudio-rs = { version = "0.3", optional = true } diff --git a/playback/src/lib.rs b/playback/src/lib.rs index f46064305..9613f2e52 100644 --- a/playback/src/lib.rs +++ b/playback/src/lib.rs @@ -1,39 +1,9 @@ #[macro_use] extern crate log; -extern crate byteorder; -extern crate futures; -extern crate shell_words; - -#[cfg(feature = "alsa-backend")] -extern crate alsa; - -#[cfg(feature = "portaudio-backend")] -extern crate portaudio_rs; - -#[cfg(feature = "pulseaudio-backend")] -extern crate libpulse_binding; -#[cfg(feature = "pulseaudio-backend")] -extern crate libpulse_simple_binding; - -#[cfg(feature = "jackaudio-backend")] -extern crate jack; - -#[cfg(feature = "gstreamer-backend")] -extern crate glib; -#[cfg(feature = "gstreamer-backend")] -extern crate gstreamer as gst; -#[cfg(feature = "gstreamer-backend")] -extern crate gstreamer_app as gst_app; -#[cfg(feature = "gstreamer-backend")] -extern crate zerocopy; - -#[cfg(feature = "sdl-backend")] -extern crate sdl2; - -extern crate librespot_audio as audio; -extern crate librespot_core; -extern crate librespot_metadata as metadata; +use librespot_audio as audio; +use librespot_core as core; +use librespot_metadata as metadata; pub mod audio_backend; pub mod config; diff --git a/playback/src/player.rs b/playback/src/player.rs index 861f91b0d..bc4a1dda1 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -1,3 +1,16 @@ +use std::borrow::Cow; +use std::cmp::max; +use std::future::Future; +use std::io::{self, Read, Seek, SeekFrom}; +use std::pin::Pin; +use std::task::{Context, Poll}; +use std::time::{Duration, Instant}; +use std::{mem, thread}; + +use byteorder::{LittleEndian, ReadBytesExt}; +use futures_util::{future, TryFutureExt}; +use tokio::sync::{mpsc, oneshot}; + use crate::audio::{AudioDecoder, AudioError, AudioPacket, PassthroughDecoder, VorbisDecoder}; use crate::audio::{AudioDecrypt, AudioFile, StreamLoaderController}; use crate::audio::{ @@ -7,23 +20,11 @@ use crate::audio::{ use crate::audio_backend::Sink; use crate::config::NormalisationType; use crate::config::{Bitrate, PlayerConfig}; +use crate::core::session::Session; +use crate::core::spotify_id::SpotifyId; +use crate::core::util::SeqGenerator; use crate::metadata::{AudioItem, FileFormat}; use crate::mixer::AudioFilter; -use librespot_core::session::Session; -use librespot_core::spotify_id::SpotifyId; -use librespot_core::util::SeqGenerator; - -use byteorder::{LittleEndian, ReadBytesExt}; -use futures::channel::{mpsc, oneshot}; -use futures::{future, Future, Stream, StreamExt, TryFutureExt}; -use std::borrow::Cow; - -use std::cmp::max; -use std::io::{self, Read, Seek, SeekFrom}; -use std::pin::Pin; -use std::task::{Context, Poll}; -use std::time::{Duration, Instant}; -use std::{mem, thread}; const PRELOAD_NEXT_TRACK_BEFORE_END_DURATION_MS: u32 = 30000; @@ -244,8 +245,8 @@ impl Player { where F: FnOnce() -> Box + Send + 'static, { - let (cmd_tx, cmd_rx) = mpsc::unbounded(); - let (event_sender, event_receiver) = mpsc::unbounded(); + let (cmd_tx, cmd_rx) = mpsc::unbounded_channel(); + let (event_sender, event_receiver) = mpsc::unbounded_channel(); let handle = thread::spawn(move || { debug!("new Player[{}]", session.session_id()); @@ -265,8 +266,8 @@ impl Player { }; // While PlayerInternal is written as a future, it still contains blocking code. - // It must be run by using wait() in a dedicated thread. - futures::executor::block_on(internal); + // It must be run by using block_on() in a dedicated thread. + futures_executor::block_on(internal); debug!("PlayerInternal thread finished."); }); @@ -281,7 +282,7 @@ impl Player { } fn command(&self, cmd: PlayerCommand) { - self.commands.as_ref().unwrap().unbounded_send(cmd).unwrap(); + self.commands.as_ref().unwrap().send(cmd).unwrap(); } pub fn load(&mut self, track_id: SpotifyId, start_playing: bool, position_ms: u32) -> u64 { @@ -317,14 +318,14 @@ impl Player { } pub fn get_player_event_channel(&self) -> PlayerEventChannel { - let (event_sender, event_receiver) = mpsc::unbounded(); + let (event_sender, event_receiver) = mpsc::unbounded_channel(); self.command(PlayerCommand::AddEventSender(event_sender)); event_receiver } - pub async fn get_end_of_track_future(&self) { + pub async fn await_end_of_track(&self) { let mut channel = self.get_player_event_channel(); - while let Some(event) = channel.next().await { + while let Some(event) = channel.recv().await { if matches!( event, PlayerEvent::EndOfTrack { .. } | PlayerEvent::Stopped { .. } @@ -797,7 +798,7 @@ impl Future for PlayerInternal { let mut all_futures_completed_or_not_ready = true; // process commands that were sent to us - let cmd = match Pin::new(&mut self.commands).poll_next(cx) { + let cmd = match self.commands.poll_recv(cx) { Poll::Ready(None) => return Poll::Ready(()), // client has disconnected - shut down. Poll::Ready(Some(cmd)) => { all_futures_completed_or_not_ready = false; @@ -1580,7 +1581,7 @@ impl PlayerInternal { fn send_event(&mut self, event: PlayerEvent) { let mut index = 0; while index < self.event_senders.len() { - match self.event_senders[index].unbounded_send(event.clone()) { + match self.event_senders[index].send(event.clone()) { Ok(_) => index += 1, Err(_) => { self.event_senders.remove(index); @@ -1608,7 +1609,7 @@ impl PlayerInternal { let (result_tx, result_rx) = oneshot::channel(); std::thread::spawn(move || { - futures::executor::block_on(loader.load_track(spotify_id, position_ms)).and_then( + futures_executor::block_on(loader.load_track(spotify_id, position_ms)).and_then( move |data| { let _ = result_tx.send(data); Some(()) From 45f42acb8299119df0ca094524081dbfb80e4303 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Mon, 22 Feb 2021 09:58:08 +0100 Subject: [PATCH 45/75] Refactor 'find_available_alternatives' --- playback/Cargo.toml | 2 +- playback/src/player.rs | 29 ++++++++++++++--------------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/playback/Cargo.toml b/playback/Cargo.toml index e32ee7ba2..96a0d264d 100644 --- a/playback/Cargo.toml +++ b/playback/Cargo.toml @@ -19,7 +19,7 @@ version = "0.1.6" [dependencies] futures-executor = { version = "0.3", default_features = false } -futures-util = { version = "0.3", default_features = false } +futures-util = { version = "0.3", default_features = false, features = ["alloc"] } log = "0.4" byteorder = "1.4" shell-words = "1.0.0" diff --git a/playback/src/player.rs b/playback/src/player.rs index bc4a1dda1..9b2c7125b 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -1,4 +1,3 @@ -use std::borrow::Cow; use std::cmp::max; use std::future::Future; use std::io::{self, Read, Seek, SeekFrom}; @@ -8,7 +7,8 @@ use std::time::{Duration, Instant}; use std::{mem, thread}; use byteorder::{LittleEndian, ReadBytesExt}; -use futures_util::{future, TryFutureExt}; +use futures_util::stream::futures_unordered::FuturesUnordered; +use futures_util::{future, StreamExt, TryFutureExt}; use tokio::sync::{mpsc, oneshot}; use crate::audio::{AudioDecoder, AudioError, AudioPacket, PassthroughDecoder, VorbisDecoder}; @@ -576,21 +576,20 @@ struct PlayerTrackLoader { } impl PlayerTrackLoader { - async fn find_available_alternative<'a, 'b>( - &'a self, - audio: &'b AudioItem, - ) -> Option> { + async fn find_available_alternative(&self, audio: AudioItem) -> Option { if audio.available { - Some(Cow::Borrowed(audio)) + Some(audio) } else if let Some(alternatives) = &audio.alternatives { - let alternatives = alternatives + let alternatives: FuturesUnordered<_> = alternatives .iter() - .map(|alt_id| AudioItem::get_audio_item(&self.session, *alt_id)); - let alternatives = future::try_join_all(alternatives).await.unwrap(); + .map(|alt_id| AudioItem::get_audio_item(&self.session, *alt_id)) + .collect(); + alternatives - .into_iter() - .find(|alt| alt.available) - .map(Cow::Owned) + .filter_map(|x| future::ready(x.ok())) + .filter(|x| future::ready(x.available)) + .next() + .await } else { None } @@ -630,10 +629,10 @@ impl PlayerTrackLoader { info!("Loading <{}> with Spotify URI <{}>", audio.name, audio.uri); - let audio = match self.find_available_alternative(&audio).await { + let audio = match self.find_available_alternative(audio).await { Some(audio) => audio, None => { - warn!("<{}> is not available", audio.uri); + warn!("<{}> is not available", spotify_id.to_uri()); return None; } }; From 27f308b82f46ce5c72eb4b3c66181046978479de Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Sat, 13 Feb 2021 11:53:23 +0100 Subject: [PATCH 46/75] Replace error_chain by thiserror --- Cargo.lock | 2 +- core/Cargo.toml | 2 +- core/src/authentication.rs | 36 ---------------------- core/src/connection/mod.rs | 63 ++++++++++++++++++++++++++++++-------- core/src/lib.rs | 2 -- core/src/session.rs | 13 ++++++-- 6 files changed, 63 insertions(+), 55 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1d6871126..d8f80b489 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1435,7 +1435,6 @@ dependencies = [ "bytes", "cfg-if 1.0.0", "env_logger", - "error-chain", "futures-core", "futures-sink", "futures-util", @@ -1455,6 +1454,7 @@ dependencies = [ "serde_json", "sha-1 0.9.4", "shannon", + "thiserror", "tokio", "tokio-stream", "tokio-util", diff --git a/core/Cargo.toml b/core/Cargo.toml index 85f3be621..0ab4e398a 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -18,7 +18,6 @@ base64 = "0.13" byteorder = "1.4" bytes = "1.0" cfg-if = "1" -error-chain = { version = "0.12", default-features = false } futures-core = { version = "0.3", default-features = false } futures-sink = { version = "0.3", default-features = false } futures-util = { version = "0.3", default-features = false, features = ["alloc", "bilock", "unstable", "sink"] } @@ -37,6 +36,7 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" sha-1 = "0.9" shannon = "0.2.0" +thiserror = "1" tokio = { version = "1.0", features = ["io-util", "net", "rt", "sync"] } tokio-stream = "0.1" tokio-util = { version = "0.6", features = ["codec"] } diff --git a/core/src/authentication.rs b/core/src/authentication.rs index ff477df56..544dda4c9 100644 --- a/core/src/authentication.rs +++ b/core/src/authentication.rs @@ -1,5 +1,4 @@ use std::io::{self, Read}; -use std::ops::FnOnce; use aes::Aes192; use byteorder::{BigEndian, ByteOrder}; @@ -10,7 +9,6 @@ use serde::{Deserialize, Serialize}; use sha1::{Digest, Sha1}; use crate::protocol::authentication::AuthenticationType; -use crate::protocol::keyexchange::{APLoginFailed, ErrorCode}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Credentials { @@ -144,37 +142,3 @@ where let v: String = serde::Deserialize::deserialize(de)?; base64::decode(&v).map_err(|e| serde::de::Error::custom(e.to_string())) } - -error_chain! { - types { - AuthenticationError, AuthenticationErrorKind, AuthenticationResultExt, AuthenticationResult; - } - - foreign_links { - Io(::std::io::Error); - } - - errors { - BadCredentials { - description("Bad credentials") - display("Authentication failed with error: Bad credentials") - } - PremiumAccountRequired { - description("Premium account required") - display("Authentication failed with error: Premium account required") - } - } -} - -impl From for AuthenticationError { - fn from(login_failure: APLoginFailed) -> Self { - let error_code = login_failure.get_error_code(); - match error_code { - ErrorCode::BadCredentials => Self::from_kind(AuthenticationErrorKind::BadCredentials), - ErrorCode::PremiumAccountRequired => { - Self::from_kind(AuthenticationErrorKind::PremiumAccountRequired) - } - _ => format!("Authentication failed with error: {:?}", error_code).into(), - } - } -} diff --git a/core/src/connection/mod.rs b/core/src/connection/mod.rs index 6bdbde6a8..a07f9a2de 100644 --- a/core/src/connection/mod.rs +++ b/core/src/connection/mod.rs @@ -4,21 +4,60 @@ mod handshake; pub use self::codec::APCodec; pub use self::handshake::handshake; -use futures_util::{SinkExt, StreamExt}; -use protobuf::{self, Message}; -use std::io; +use std::io::{self, ErrorKind}; use std::net::ToSocketAddrs; + +use futures_util::{SinkExt, StreamExt}; +use protobuf::{self, Message, ProtobufError}; +use thiserror::Error; use tokio::net::TcpStream; use tokio_util::codec::Framed; use url::Url; -use crate::authentication::{AuthenticationError, Credentials}; -use crate::version; - +use crate::authentication::Credentials; +use crate::protocol::keyexchange::{APLoginFailed, ErrorCode}; use crate::proxytunnel; +use crate::version; pub type Transport = Framed; +fn login_error_message(code: &ErrorCode) -> &'static str { + pub use ErrorCode::*; + match code { + ProtocolError => "Protocol error", + TryAnotherAP => "Try another AP", + BadConnectionId => "Bad connection id", + TravelRestriction => "Travel restriction", + PremiumAccountRequired => "Premium account required", + BadCredentials => "Bad credentials", + CouldNotValidateCredentials => "Could not validate credentials", + AccountExists => "Account exists", + ExtraVerificationRequired => "Extra verification required", + InvalidAppKey => "Invalid app key", + ApplicationBanned => "Application banned", + } +} + +#[derive(Debug, Error)] +pub enum AuthenticationError { + #[error("Login failed with reason: {}", login_error_message(.0))] + LoginFailed(ErrorCode), + #[error("Authentication failed: {0}")] + IoError(#[from] io::Error), +} + +impl From for AuthenticationError { + fn from(e: ProtobufError) -> Self { + io::Error::new(ErrorKind::InvalidData, e).into() + } +} + +impl From for AuthenticationError { + fn from(login_failure: APLoginFailed) -> Self { + Self::LoginFailed(login_failure.get_error_code()) + } +} + pub async fn connect(addr: String, proxy: &Option) -> io::Result { let socket = if let Some(proxy) = proxy { info!("Using proxy \"{}\"", proxy); @@ -66,7 +105,6 @@ pub async fn authenticate( device_id: &str, ) -> Result { use crate::protocol::authentication::{APWelcome, ClientResponseEncrypted, CpuFamily, Os}; - use crate::protocol::keyexchange::APLoginFailed; let mut packet = ClientResponseEncrypted::new(); packet @@ -101,7 +139,7 @@ pub async fn authenticate( let (cmd, data) = transport.next().await.expect("EOF")?; match cmd { 0xac => { - let welcome_data: APWelcome = protobuf::parse_from_bytes(data.as_ref()).unwrap(); + let welcome_data: APWelcome = protobuf::parse_from_bytes(data.as_ref())?; let reusable_credentials = Credentials { username: welcome_data.get_canonical_username().to_owned(), @@ -111,12 +149,13 @@ pub async fn authenticate( Ok(reusable_credentials) } - 0xad => { - let error_data: APLoginFailed = protobuf::parse_from_bytes(data.as_ref()).unwrap(); + let error_data: APLoginFailed = protobuf::parse_from_bytes(data.as_ref())?; Err(error_data.into()) } - - _ => panic!("Unexpected packet {:?}", cmd), + _ => { + let msg = format!("Received invalid packet: {}", cmd); + Err(io::Error::new(ErrorKind::InvalidData, msg).into()) + } } } diff --git a/core/src/lib.rs b/core/src/lib.rs index 54f83f17e..4ebe85819 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -4,8 +4,6 @@ extern crate log; #[macro_use] extern crate cfg_if; -#[macro_use] -extern crate error_chain; use librespot_protocol as protocol; diff --git a/core/src/session.rs b/core/src/session.rs index 858a0b696..9eaff3ed5 100644 --- a/core/src/session.rs +++ b/core/src/session.rs @@ -12,6 +12,7 @@ use bytes::Bytes; use futures_core::TryStream; use futures_util::{FutureExt, StreamExt, TryStreamExt}; use once_cell::sync::OnceCell; +use thiserror::Error; use tokio::sync::mpsc; use tokio_stream::wrappers::UnboundedReceiverStream; @@ -21,10 +22,16 @@ use crate::authentication::Credentials; use crate::cache::Cache; use crate::channel::ChannelManager; use crate::config::SessionConfig; -use crate::connection; +use crate::connection::{self, AuthenticationError}; use crate::mercury::MercuryManager; -pub use crate::authentication::{AuthenticationError, AuthenticationErrorKind}; +#[derive(Debug, Error)] +pub enum SessionError { + #[error(transparent)] + AuthenticationError(#[from] AuthenticationError), + #[error("Cannot create session: {0}")] + IoError(#[from] io::Error), +} struct SessionData { country: String, @@ -59,7 +66,7 @@ impl Session { config: SessionConfig, credentials: Credentials, cache: Option, - ) -> Result { + ) -> Result { let ap = apresolve_or_fallback(&config.proxy, &config.ap_port).await; info!("Connecting to AP \"{}\"", ap); From f9c0e26f6df22fa0bbb1e37e9546c5ed778195ec Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Sat, 13 Feb 2021 15:38:05 +0100 Subject: [PATCH 47/75] Simplify code --- audio/src/fetch.rs | 77 ++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 41 deletions(-) diff --git a/audio/src/fetch.rs b/audio/src/fetch.rs index 0ec9b01df..ccbb89892 100644 --- a/audio/src/fetch.rs +++ b/audio/src/fetch.rs @@ -449,7 +449,7 @@ enum ReceivedData { async fn audio_file_fetch_receive_data( shared: Arc, file_data_tx: mpsc::UnboundedSender, - data_rx: ChannelData, + mut data_rx: ChannelData, initial_data_offset: usize, initial_request_length: usize, request_sent_time: Instant, @@ -465,49 +465,44 @@ async fn audio_file_fetch_receive_data( .number_of_open_requests .fetch_add(1, atomic::Ordering::SeqCst); - enum TryFoldErr { - ChannelError, - FinishEarly, - } + let result = loop { + let data = match data_rx.next().await { + Some(Ok(data)) => data, + Some(Err(e)) => break Err(e), + None => break Ok(()), + }; - let result = data_rx - .map_err(|_| TryFoldErr::ChannelError) - .try_for_each(|data| { - if measure_ping_time { - let duration = Instant::now() - request_sent_time; - let duration_ms: u64; - if 0.001 * (duration.as_millis() as f64) - > MAXIMUM_ASSUMED_PING_TIME_SECONDS - { - duration_ms = (MAXIMUM_ASSUMED_PING_TIME_SECONDS * 1000.0) as u64; - } else { - duration_ms = duration.as_millis() as u64; - } - let _ = file_data_tx - .send(ReceivedData::ResponseTimeMs(duration_ms as usize)); - measure_ping_time = false; - } - let data_size = data.len(); - let _ = file_data_tx - .send(ReceivedData::Data(PartialFileData { - offset: data_offset, - data: data, - })); - data_offset += data_size; - if request_length < data_size { - warn!("Data receiver for range {} (+{}) received more data from server than requested.", initial_data_offset, initial_request_length); - request_length = 0; + if measure_ping_time { + let duration = Instant::now() - request_sent_time; + let duration_ms: u64; + if 0.001 * (duration.as_millis() as f64) > MAXIMUM_ASSUMED_PING_TIME_SECONDS { + duration_ms = (MAXIMUM_ASSUMED_PING_TIME_SECONDS * 1000.0) as u64; } else { - request_length -= data_size; + duration_ms = duration.as_millis() as u64; } + let _ = file_data_tx.send(ReceivedData::ResponseTimeMs(duration_ms as usize)); + measure_ping_time = false; + } + let data_size = data.len(); + let _ = file_data_tx.send(ReceivedData::Data(PartialFileData { + offset: data_offset, + data: data, + })); + data_offset += data_size; + if request_length < data_size { + warn!( + "Data receiver for range {} (+{}) received more data from server than requested.", + initial_data_offset, initial_request_length + ); + request_length = 0; + } else { + request_length -= data_size; + } - future::ready(if request_length == 0 { - Err(TryFoldErr::FinishEarly) - } else { - Ok(()) - }) - }) - .await; + if request_length == 0 { + break Ok(()); + } + }; if request_length > 0 { let missing_range = Range::new(data_offset, request_length); @@ -521,7 +516,7 @@ async fn audio_file_fetch_receive_data( .number_of_open_requests .fetch_sub(1, atomic::Ordering::SeqCst); - if let Err(TryFoldErr::ChannelError) = result { + if result.is_err() { warn!( "Error from channel for data receiver for range {} (+{}).", initial_data_offset, initial_request_length From d064ffc670a28962eb73c50e04ad001c1a478e08 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Sun, 21 Feb 2021 19:38:40 +0100 Subject: [PATCH 48/75] Use tokio channels and fix compilation errors --- Cargo.lock | 3 ++- Cargo.toml | 2 +- connect/Cargo.toml | 3 ++- connect/src/spirc.rs | 39 ++++++++++++++++++++++----------------- src/main.rs | 5 +++-- 5 files changed, 30 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d8f80b489..16da85e41 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1416,12 +1416,13 @@ dependencies = [ "log", "num-bigint", "protobuf", - "rand 0.7.3", + "rand 0.8.3", "serde", "serde_derive", "serde_json", "sha-1 0.9.4", "tokio", + "tokio-stream", "url 1.7.2", ] diff --git a/Cargo.toml b/Cargo.toml index a26db2ed6..93866e290 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,7 +55,7 @@ num-bigint = "0.3" protobuf = "~2.14.0" rand = "0.7" rpassword = "5.0" -tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros", "signal", "process"] } +tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros", "signal", "sync", "process"] } url = "1.7" sha-1 = "0.8" hex = "0.4" diff --git a/connect/Cargo.toml b/connect/Cargo.toml index 1ca6d7dba..4997c5fba 100644 --- a/connect/Cargo.toml +++ b/connect/Cargo.toml @@ -27,12 +27,13 @@ hyper = { version = "0.14", features = ["server", "http1"] } log = "0.4" num-bigint = "0.3" protobuf = "~2.14.0" -rand = "0.7" +rand = "0.8" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" sha-1 = "0.9" tokio = { version = "1.0", features = ["macros"] } +tokio-stream = { version = "0.1" } url = "1.7" dns-sd = { version = "0.1.3", optional = true } diff --git a/connect/src/spirc.rs b/connect/src/spirc.rs index 50307595f..dd495d82d 100644 --- a/connect/src/spirc.rs +++ b/connect/src/spirc.rs @@ -6,7 +6,7 @@ use crate::playback::mixer::Mixer; use crate::playback::player::{Player, PlayerEvent, PlayerEventChannel}; use crate::protocol; use crate::protocol::spirc::{DeviceState, Frame, MessageType, PlayStatus, State, TrackRef}; -use futures::channel::mpsc; + use futures::future::{self, FusedFuture}; use futures::stream::FusedStream; use futures::{Future, FutureExt, StreamExt}; @@ -21,6 +21,8 @@ use protobuf::{self, Message}; use rand; use rand::seq::SliceRandom; use serde_json; +use tokio::sync::mpsc; +use tokio_stream::wrappers::UnboundedReceiverStream; enum SpircPlayStatus { Stopped, @@ -59,8 +61,8 @@ struct SpircTask { subscription: BoxedStream, sender: MercurySender, - commands: mpsc::UnboundedReceiver, - player_events: PlayerEventChannel, + commands: Option>, + player_events: Option, shutdown: bool, session: Session, @@ -263,6 +265,7 @@ impl Spirc { .mercury() .subscribe(uri.clone()) .map(Result::unwrap) + .map(UnboundedReceiverStream::new) .flatten_stream() .map(|response| -> Frame { let data = response.payload.first().unwrap(); @@ -272,7 +275,7 @@ impl Spirc { let sender = session.mercury().sender(uri); - let (cmd_tx, cmd_rx) = mpsc::unbounded(); + let (cmd_tx, cmd_rx) = mpsc::unbounded_channel(); let volume = config.volume; let task_config = SpircTaskConfig { @@ -301,8 +304,8 @@ impl Spirc { subscription: subscription, sender: sender, - commands: cmd_rx, - player_events: player_events, + commands: Some(cmd_rx), + player_events: Some(player_events), shutdown: false, session: session, @@ -322,34 +325,36 @@ impl Spirc { } pub fn play(&self) { - let _ = self.commands.unbounded_send(SpircCommand::Play); + let _ = self.commands.send(SpircCommand::Play); } pub fn play_pause(&self) { - let _ = self.commands.unbounded_send(SpircCommand::PlayPause); + let _ = self.commands.send(SpircCommand::PlayPause); } pub fn pause(&self) { - let _ = self.commands.unbounded_send(SpircCommand::Pause); + let _ = self.commands.send(SpircCommand::Pause); } pub fn prev(&self) { - let _ = self.commands.unbounded_send(SpircCommand::Prev); + let _ = self.commands.send(SpircCommand::Prev); } pub fn next(&self) { - let _ = self.commands.unbounded_send(SpircCommand::Next); + let _ = self.commands.send(SpircCommand::Next); } pub fn volume_up(&self) { - let _ = self.commands.unbounded_send(SpircCommand::VolumeUp); + let _ = self.commands.send(SpircCommand::VolumeUp); } pub fn volume_down(&self) { - let _ = self.commands.unbounded_send(SpircCommand::VolumeDown); + let _ = self.commands.send(SpircCommand::VolumeDown); } pub fn shutdown(&self) { - let _ = self.commands.unbounded_send(SpircCommand::Shutdown); + let _ = self.commands.send(SpircCommand::Shutdown); } } impl SpircTask { async fn run(mut self) { while !self.session.is_invalid() && !self.shutdown { + let commands = self.commands.as_mut(); + let player_events = self.player_events.as_mut(); tokio::select! { frame = self.subscription.next() => match frame { Some(frame) => self.handle_frame(frame), @@ -358,10 +363,10 @@ impl SpircTask { break; } }, - cmd = self.commands.next(), if !self.commands.is_terminated() => if let Some(cmd) = cmd { + cmd = async { commands.unwrap().recv().await }, if commands.is_some() => if let Some(cmd) = cmd { self.handle_command(cmd); }, - event = self.player_events.next(), if !self.player_events.is_terminated() => if let Some(event) = event { + event = async { player_events.unwrap().recv().await }, if player_events.is_some() => if let Some(event) = event { self.handle_player_event(event) }, result = self.sender.flush(), if !self.sender.is_flushed() => if result.is_err() { @@ -508,7 +513,7 @@ impl SpircTask { SpircCommand::Shutdown => { CommandSender::new(self, MessageType::kMessageTypeGoodbye).send(); self.shutdown = true; - self.commands.close(); + self.commands.as_mut().map(|rx| rx.close()); } } } diff --git a/src/main.rs b/src/main.rs index 31ef30019..7882203bd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use futures::{channel::mpsc::UnboundedReceiver, future::FusedFuture, FutureExt, StreamExt}; +use futures::{future::FusedFuture, FutureExt, StreamExt}; use librespot_playback::player::PlayerEvent; use log::{error, info, warn}; use sha1::{Digest, Sha1}; @@ -10,6 +10,7 @@ use std::{ io::{stderr, Write}, pin::Pin, }; +use tokio::sync::mpsc::UnboundedReceiver; use url::Url; use librespot::core::authentication::Credentials; @@ -589,7 +590,7 @@ async fn main() { } } }, - event = async { player_event_channel.as_mut().unwrap().next().await }, if player_event_channel.is_some() => match event { + event = async { player_event_channel.as_mut().unwrap().recv().await }, if player_event_channel.is_some() => match event { Some(event) => { if let Some(program) = &setupp.player_event_program { if let Some(child) = run_program_on_events(event, program) { From 59c556635ebbd20897e8c739e3395da2decd5742 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Sun, 21 Feb 2021 19:38:44 +0100 Subject: [PATCH 49/75] Clean up librespot-connect dependencies --- Cargo.lock | 4 ++-- connect/Cargo.toml | 33 ++++++++++++++++++--------------- connect/src/context.rs | 4 ++-- connect/src/discovery.rs | 12 ++++++------ connect/src/lib.rs | 31 +++---------------------------- connect/src/spirc.rs | 23 +++++++++++------------ 6 files changed, 42 insertions(+), 65 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 16da85e41..1aaf97048 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1406,7 +1406,8 @@ dependencies = [ "base64", "block-modes", "dns-sd", - "futures", + "futures-core", + "futures-util", "hmac", "hyper", "libmdns", @@ -1418,7 +1419,6 @@ dependencies = [ "protobuf", "rand 0.8.3", "serde", - "serde_derive", "serde_json", "sha-1 0.9.4", "tokio", diff --git a/connect/Cargo.toml b/connect/Cargo.toml index 4997c5fba..f1d4a389f 100644 --- a/connect/Cargo.toml +++ b/connect/Cargo.toml @@ -7,39 +7,42 @@ license = "MIT" repository = "https://github.com/librespot-org/librespot" edition = "2018" -[dependencies.librespot-core] -path = "../core" -version = "0.1.6" -[dependencies.librespot-playback] -path = "../playback" -version = "0.1.6" -[dependencies.librespot-protocol] -path = "../protocol" -version = "0.1.6" - [dependencies] aes-ctr = "0.6" base64 = "0.13" block-modes = "0.7" -futures = "0.3" +futures-core = "0.3" +futures-util = "0.3" hmac = "0.10" hyper = { version = "0.14", features = ["server", "http1"] } log = "0.4" num-bigint = "0.3" protobuf = "~2.14.0" rand = "0.8" -serde = "1.0" -serde_derive = "1.0" +serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" sha-1 = "0.9" -tokio = { version = "1.0", features = ["macros"] } +tokio = { version = "1.0", features = ["macros", "sync"] } tokio-stream = { version = "0.1" } url = "1.7" dns-sd = { version = "0.1.3", optional = true } libmdns = { version = "0.6", optional = true } +[dependencies.librespot-core] +path = "../core" +version = "0.1.6" + +[dependencies.librespot-playback] +path = "../playback" +version = "0.1.6" + +[dependencies.librespot-protocol] +path = "../protocol" +version = "0.1.6" [features] -default = ["libmdns"] +with-libmdns = ["libmdns"] with-dns-sd = ["dns-sd"] + +default = ["with-libmdns"] diff --git a/connect/src/context.rs b/connect/src/context.rs index 5a94f6cb7..63a2aebb4 100644 --- a/connect/src/context.rs +++ b/connect/src/context.rs @@ -1,7 +1,7 @@ +use crate::core::spotify_id::SpotifyId; use crate::protocol::spirc::TrackRef; -use librespot_core::spotify_id::SpotifyId; -use serde; +use serde::Deserialize; #[derive(Deserialize, Debug)] pub struct StationContext { diff --git a/connect/src/discovery.rs b/connect/src/discovery.rs index 2951b3819..1c94ecc8f 100644 --- a/connect/src/discovery.rs +++ b/connect/src/discovery.rs @@ -1,13 +1,13 @@ use aes_ctr::cipher::generic_array::GenericArray; use aes_ctr::cipher::{NewStreamCipher, SyncStreamCipher}; use aes_ctr::Aes128Ctr; -use base64; -use futures::channel::{mpsc, oneshot}; -use futures::{Stream, StreamExt}; +use futures_core::Stream; use hmac::{Hmac, Mac, NewMac}; use hyper::service::{make_service_fn, service_fn}; use hyper::{Body, Method, Request, Response, StatusCode}; +use serde_json::json; use sha1::{Digest, Sha1}; +use tokio::sync::{mpsc, oneshot}; use std::borrow::Cow; use std::convert::Infallible; @@ -50,7 +50,7 @@ impl Discovery { config: ConnectConfig, device_id: String, ) -> (Discovery, mpsc::UnboundedReceiver) { - let (tx, rx) = mpsc::unbounded(); + let (tx, rx) = mpsc::unbounded_channel(); let key_data = util::rand_vec(&mut rand::thread_rng(), 95); let private_key = BigUint::from_bytes_be(&key_data); @@ -155,7 +155,7 @@ impl Discovery { let credentials = Credentials::with_blob(username.to_string(), &decrypted, &self.0.device_id); - self.0.tx.unbounded_send(credentials).unwrap(); + self.0.tx.send(credentials).unwrap(); let result = json!({ "status": 101, @@ -273,6 +273,6 @@ impl Stream for DiscoveryStream { type Item = Credentials; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.credentials.poll_next_unpin(cx) + self.credentials.poll_recv(cx) } } diff --git a/connect/src/lib.rs b/connect/src/lib.rs index 47777606e..600dd0335 100644 --- a/connect/src/lib.rs +++ b/connect/src/lib.rs @@ -1,34 +1,9 @@ #[macro_use] extern crate log; -#[macro_use] -extern crate serde_json; -#[macro_use] -extern crate serde_derive; -extern crate serde; - -extern crate base64; -extern crate futures; -extern crate hyper; -extern crate num_bigint; -extern crate protobuf; -extern crate rand; -extern crate tokio; -extern crate url; - -extern crate aes_ctr; -extern crate block_modes; -extern crate hmac; -extern crate sha1; - -#[cfg(feature = "with-dns-sd")] -extern crate dns_sd; - -#[cfg(not(feature = "with-dns-sd"))] -extern crate libmdns; -extern crate librespot_core; -extern crate librespot_playback as playback; -extern crate librespot_protocol as protocol; +use librespot_core as core; +use librespot_playback as playback; +use librespot_protocol as protocol; pub mod context; pub mod discovery; diff --git a/connect/src/spirc.rs b/connect/src/spirc.rs index dd495d82d..5afefe7f9 100644 --- a/connect/src/spirc.rs +++ b/connect/src/spirc.rs @@ -1,26 +1,25 @@ +use std::future::Future; use std::pin::Pin; use std::time::{SystemTime, UNIX_EPOCH}; use crate::context::StationContext; +use crate::core::config::{ConnectConfig, VolumeCtrl}; +use crate::core::mercury::{MercuryError, MercurySender}; +use crate::core::session::Session; +use crate::core::spotify_id::{SpotifyAudioType, SpotifyId, SpotifyIdError}; +use crate::core::util::url_encode; +use crate::core::util::SeqGenerator; +use crate::core::version; use crate::playback::mixer::Mixer; use crate::playback::player::{Player, PlayerEvent, PlayerEventChannel}; use crate::protocol; use crate::protocol::spirc::{DeviceState, Frame, MessageType, PlayStatus, State, TrackRef}; -use futures::future::{self, FusedFuture}; -use futures::stream::FusedStream; -use futures::{Future, FutureExt, StreamExt}; -use librespot_core::config::{ConnectConfig, VolumeCtrl}; -use librespot_core::mercury::{MercuryError, MercurySender}; -use librespot_core::session::Session; -use librespot_core::spotify_id::{SpotifyAudioType, SpotifyId, SpotifyIdError}; -use librespot_core::util::url_encode; -use librespot_core::util::SeqGenerator; -use librespot_core::version; +use futures_util::future::{self, FusedFuture}; +use futures_util::stream::FusedStream; +use futures_util::{FutureExt, StreamExt}; use protobuf::{self, Message}; -use rand; use rand::seq::SliceRandom; -use serde_json; use tokio::sync::mpsc; use tokio_stream::wrappers::UnboundedReceiverStream; From 18179e73eccd547b0a6bd1272922aa597ab7c9f8 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Sun, 21 Feb 2021 19:38:49 +0100 Subject: [PATCH 50/75] Remove unused dependencies and fix feature flags --- Cargo.lock | 208 ++++++-------------------------------------- Cargo.toml | 9 +- connect/Cargo.toml | 6 +- core/Cargo.toml | 1 - playback/Cargo.toml | 2 +- src/main.rs | 5 +- 6 files changed, 35 insertions(+), 196 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1aaf97048..426d4fd9c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -51,7 +51,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" dependencies = [ "cipher", - "opaque-debug 0.3.0", + "opaque-debug", ] [[package]] @@ -61,7 +61,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" dependencies = [ "cipher", - "opaque-debug 0.3.0", + "opaque-debug", ] [[package]] @@ -186,25 +186,13 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -[[package]] -name = "block-buffer" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -dependencies = [ - "block-padding 0.1.5", - "byte-tools", - "byteorder", - "generic-array 0.12.3", -] - [[package]] name = "block-buffer" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "generic-array 0.14.4", + "generic-array", ] [[package]] @@ -213,19 +201,10 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57a0e8073e8baa88212fb5823574c02ebccb395136ba9a164ab89379ec6072f0" dependencies = [ - "block-padding 0.2.1", + "block-padding", "cipher", ] -[[package]] -name = "block-padding" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" -dependencies = [ - "byte-tools", -] - [[package]] name = "block-padding" version = "0.2.1" @@ -238,12 +217,6 @@ version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe" -[[package]] -name = "byte-tools" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" - [[package]] name = "byteorder" version = "1.4.2" @@ -314,7 +287,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" dependencies = [ - "generic-array 0.14.4", + "generic-array", ] [[package]] @@ -456,7 +429,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4857fd85a0c34b3c3297875b747c1e02e06b6a0ea32dd892d8192b9ce0813ea6" dependencies = [ - "generic-array 0.14.4", + "generic-array", "subtle", ] @@ -515,22 +488,13 @@ dependencies = [ "syn", ] -[[package]] -name = "digest" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -dependencies = [ - "generic-array 0.12.3", -] - [[package]] name = "digest" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array 0.14.4", + "generic-array", ] [[package]] @@ -578,12 +542,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" - [[package]] name = "fetch_unroll" version = "0.2.2" @@ -623,21 +581,6 @@ dependencies = [ "percent-encoding 2.1.0", ] -[[package]] -name = "futures" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f55667319111d593ba876406af7c409c0ebb44dc4be6132a783ccf163ea14c1" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - [[package]] name = "futures-channel" version = "0.3.13" @@ -645,7 +588,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c2dd2df839b57db9ab69c2c9d8f3e8c81984781937fe2807dc6dcf3b2ad2939" dependencies = [ "futures-core", - "futures-sink", ] [[package]] @@ -665,12 +607,6 @@ dependencies = [ "futures-util", ] -[[package]] -name = "futures-io" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71c2c65c57704c32f5241c1223167c2c3294fd34ac020c807ddbe6db287ba59" - [[package]] name = "futures-macro" version = "0.3.13" @@ -701,13 +637,10 @@ version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1812c7ab8aedf8d6f2701a43e1243acdbcc2b36ab26e2ad421eb99ac963d96d1" dependencies = [ - "futures-channel", "futures-core", - "futures-io", "futures-macro", "futures-sink", "futures-task", - "memchr", "pin-project-lite", "pin-utils", "proc-macro-hack", @@ -721,15 +654,6 @@ version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" -[[package]] -name = "generic-array" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" -dependencies = [ - "typenum", -] - [[package]] name = "generic-array" version = "0.14.4" @@ -749,17 +673,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.2" @@ -768,7 +681,7 @@ checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" dependencies = [ "cfg-if 1.0.0", "libc", - "wasi 0.10.2+wasi-snapshot-preview1", + "wasi", ] [[package]] @@ -994,7 +907,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" dependencies = [ "crypto-mac", - "digest 0.9.0", + "digest", ] [[package]] @@ -1300,7 +1213,7 @@ dependencies = [ "log", "multimap", "quick-error", - "rand 0.8.3", + "rand", "socket2", "tokio", ] @@ -1359,7 +1272,7 @@ version = "0.1.6" dependencies = [ "base64", "env_logger", - "futures", + "futures-util", "getopts", "hex", "hyper", @@ -1370,11 +1283,8 @@ dependencies = [ "librespot-playback", "librespot-protocol", "log", - "num-bigint", - "protobuf", - "rand 0.7.3", "rpassword", - "sha-1 0.8.2", + "sha-1", "tokio", "url 1.7.2", ] @@ -1417,10 +1327,10 @@ dependencies = [ "log", "num-bigint", "protobuf", - "rand 0.8.3", + "rand", "serde", "serde_json", - "sha-1 0.9.4", + "sha-1", "tokio", "tokio-stream", "url 1.7.2", @@ -1437,7 +1347,6 @@ dependencies = [ "cfg-if 1.0.0", "env_logger", "futures-core", - "futures-sink", "futures-util", "hmac", "httparse", @@ -1450,10 +1359,10 @@ dependencies = [ "once_cell", "pbkdf2", "protobuf", - "rand 0.8.3", + "rand", "serde", "serde_json", - "sha-1 0.9.4", + "sha-1", "shannon", "thiserror", "tokio", @@ -1835,12 +1744,6 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ad167a2f54e832b82dbe003a046280dceffe5227b5f79e08e363a29638cfddd" -[[package]] -name = "opaque-debug" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" - [[package]] name = "opaque-debug" version = "0.3.0" @@ -2102,19 +2005,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc 0.2.0", -] - [[package]] name = "rand" version = "0.8.3" @@ -2122,19 +2012,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" dependencies = [ "libc", - "rand_chacha 0.3.0", - "rand_core 0.6.2", - "rand_hc 0.3.0", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", + "rand_chacha", + "rand_core", + "rand_hc", ] [[package]] @@ -2144,16 +2024,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" dependencies = [ "ppv-lite86", - "rand_core 0.6.2", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", + "rand_core", ] [[package]] @@ -2162,16 +2033,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" dependencies = [ - "getrandom 0.2.2", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", + "getrandom", ] [[package]] @@ -2180,7 +2042,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" dependencies = [ - "rand_core 0.6.2", + "rand_core", ] [[package]] @@ -2420,29 +2282,17 @@ dependencies = [ "serde", ] -[[package]] -name = "sha-1" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" -dependencies = [ - "block-buffer 0.7.3", - "digest 0.8.1", - "fake-simd", - "opaque-debug 0.2.3", -] - [[package]] name = "sha-1" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfebf75d25bd900fd1e7d11501efab59bc846dbc76196839663e6637bba9f25f" dependencies = [ - "block-buffer 0.9.0", + "block-buffer", "cfg-if 1.0.0", "cpuid-bool", - "digest 0.9.0", - "opaque-debug 0.3.0", + "digest", + "opaque-debug", ] [[package]] @@ -2661,7 +2511,7 @@ checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ "cfg-if 1.0.0", "libc", - "rand 0.8.3", + "rand", "redox_syscall", "remove_dir_all", "winapi", @@ -3066,12 +2916,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index 93866e290..6e5ca0328 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,18 +47,15 @@ version = "0.1.6" [dependencies] base64 = "0.13" env_logger = {version = "0.8", default-features = false, features = ["termcolor","humantime","atty"]} -futures = "0.3" +futures-util = { version = "0.3", default_features = false } getopts = "0.2" +hex = "0.4" hyper = "0.14" log = "0.4" -num-bigint = "0.3" -protobuf = "~2.14.0" -rand = "0.7" rpassword = "5.0" tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros", "signal", "sync", "process"] } url = "1.7" -sha-1 = "0.8" -hex = "0.4" +sha-1 = "0.9" [features] apresolve = ["librespot-core/apresolve"] diff --git a/connect/Cargo.toml b/connect/Cargo.toml index f1d4a389f..554764668 100644 --- a/connect/Cargo.toml +++ b/connect/Cargo.toml @@ -12,9 +12,9 @@ aes-ctr = "0.6" base64 = "0.13" block-modes = "0.7" futures-core = "0.3" -futures-util = "0.3" +futures-util = { version = "0.3", default_features = false } hmac = "0.10" -hyper = { version = "0.14", features = ["server", "http1"] } +hyper = { version = "0.14", features = ["server", "http1", "tcp"] } log = "0.4" num-bigint = "0.3" protobuf = "~2.14.0" @@ -22,7 +22,7 @@ rand = "0.8" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" sha-1 = "0.9" -tokio = { version = "1.0", features = ["macros", "sync"] } +tokio = { version = "1.0", features = ["macros", "rt", "sync"] } tokio-stream = { version = "0.1" } url = "1.7" diff --git a/core/Cargo.toml b/core/Cargo.toml index 0ab4e398a..5c5fa6007 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -19,7 +19,6 @@ byteorder = "1.4" bytes = "1.0" cfg-if = "1" futures-core = { version = "0.3", default-features = false } -futures-sink = { version = "0.3", default-features = false } futures-util = { version = "0.3", default-features = false, features = ["alloc", "bilock", "unstable", "sink"] } hmac = "0.10" httparse = "1.3" diff --git a/playback/Cargo.toml b/playback/Cargo.toml index 96a0d264d..03675de81 100644 --- a/playback/Cargo.toml +++ b/playback/Cargo.toml @@ -18,7 +18,7 @@ path = "../metadata" version = "0.1.6" [dependencies] -futures-executor = { version = "0.3", default_features = false } +futures-executor = "0.3" futures-util = { version = "0.3", default_features = false, features = ["alloc"] } log = "0.4" byteorder = "1.4" diff --git a/src/main.rs b/src/main.rs index 7882203bd..5de83de14 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use futures::{future::FusedFuture, FutureExt, StreamExt}; +use futures_util::{future, FutureExt, StreamExt}; use librespot_playback::player::PlayerEvent; use log::{error, info, warn}; use sha1::{Digest, Sha1}; @@ -468,8 +468,7 @@ async fn main() { let mut player_event_channel: Option> = None; let mut auto_connect_times: Vec = vec![]; let mut discovery = None; - let mut connecting: Pin>> = - Box::pin(futures::future::pending()); + let mut connecting: Pin>> = Box::pin(future::pending()); if setupp.enable_discovery { let config = setupp.connect_config.clone(); From b606d8c661fd6ad6f5cdcedfb04eadbd644b2d3a Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Sun, 21 Feb 2021 19:38:52 +0100 Subject: [PATCH 51/75] Replace "extern crate"s --- src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7cdd31789..7722e93e6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,8 @@ #![crate_name = "librespot"] -pub extern crate librespot_audio as audio; -pub extern crate librespot_connect as connect; -pub extern crate librespot_core as core; -pub extern crate librespot_metadata as metadata; -pub extern crate librespot_playback as playback; -pub extern crate librespot_protocol as protocol; +pub use librespot_audio as audio; +pub use librespot_connect as connect; +pub use librespot_core as core; +pub use librespot_metadata as metadata; +pub use librespot_playback as playback; +pub use librespot_protocol as protocol; From f22b41956f55c481d270c41ca17656027296bfe1 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Mon, 22 Feb 2021 11:26:12 +0100 Subject: [PATCH 52/75] Update url crate to 2.1 --- Cargo.lock | 54 +++++++++----------------------------- Cargo.toml | 2 +- connect/Cargo.toml | 2 +- core/Cargo.toml | 2 +- core/src/apresolve.rs | 2 +- core/src/connection/mod.rs | 4 +-- 6 files changed, 19 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 426d4fd9c..65493a277 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -336,7 +336,7 @@ version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "784ad0fbab4f3e9cef09f20e0aea6000ae08d2cb98ac4c0abc53df18803d702f" dependencies = [ - "percent-encoding 2.1.0", + "percent-encoding", "time 0.2.25", "version_check", ] @@ -348,13 +348,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3818dfca4b0cb5211a659bbcbb94225b7127407b2b135e650d717bfb78ab10d3" dependencies = [ "cookie", - "idna 0.2.2", + "idna", "log", "publicsuffix", "serde", "serde_json", "time 0.2.25", - "url 2.2.1", + "url", ] [[package]] @@ -578,7 +578,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" dependencies = [ "matches", - "percent-encoding 2.1.0", + "percent-encoding", ] [[package]] @@ -990,17 +990,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" -[[package]] -name = "idna" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "idna" version = "0.2.2" @@ -1286,7 +1275,7 @@ dependencies = [ "rpassword", "sha-1", "tokio", - "url 1.7.2", + "url", ] [[package]] @@ -1333,7 +1322,7 @@ dependencies = [ "sha-1", "tokio", "tokio-stream", - "url 1.7.2", + "url", ] [[package]] @@ -1368,7 +1357,7 @@ dependencies = [ "tokio", "tokio-stream", "tokio-util", - "url 1.7.2", + "url", "vergen", ] @@ -1797,12 +1786,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" -[[package]] -name = "percent-encoding" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" - [[package]] name = "percent-encoding" version = "2.1.0" @@ -1975,10 +1958,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bbaa49075179162b49acac1c6aa45fb4dafb5f13cf6794276d77bc7fd95757b" dependencies = [ "error-chain", - "idna 0.2.2", + "idna", "lazy_static", "regex", - "url 2.2.1", + "url", ] [[package]] @@ -1987,7 +1970,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" dependencies = [ - "percent-encoding 2.1.0", + "percent-encoding", ] [[package]] @@ -2801,22 +2784,11 @@ dependencies = [ "once_cell", "qstring", "rustls", - "url 2.2.1", + "url", "webpki", "webpki-roots", ] -[[package]] -name = "url" -version = "1.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" -dependencies = [ - "idna 0.1.5", - "matches", - "percent-encoding 1.0.1", -] - [[package]] name = "url" version = "2.2.1" @@ -2824,9 +2796,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b" dependencies = [ "form_urlencoded", - "idna 0.2.2", + "idna", "matches", - "percent-encoding 2.1.0", + "percent-encoding", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 6e5ca0328..6b8cbee50 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,7 +54,7 @@ hyper = "0.14" log = "0.4" rpassword = "5.0" tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros", "signal", "sync", "process"] } -url = "1.7" +url = "2.1" sha-1 = "0.9" [features] diff --git a/connect/Cargo.toml b/connect/Cargo.toml index 554764668..b03de885f 100644 --- a/connect/Cargo.toml +++ b/connect/Cargo.toml @@ -24,7 +24,7 @@ serde_json = "1.0" sha-1 = "0.9" tokio = { version = "1.0", features = ["macros", "rt", "sync"] } tokio-stream = { version = "0.1" } -url = "1.7" +url = "2.1" dns-sd = { version = "0.1.3", optional = true } libmdns = { version = "0.6", optional = true } diff --git a/core/Cargo.toml b/core/Cargo.toml index 5c5fa6007..373e30885 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -39,7 +39,7 @@ thiserror = "1" tokio = { version = "1.0", features = ["io-util", "net", "rt", "sync"] } tokio-stream = "0.1" tokio-util = { version = "0.6", features = ["codec"] } -url = "1.7" +url = "2.1" [build-dependencies] rand = "0.8" diff --git a/core/src/apresolve.rs b/core/src/apresolve.rs index 7698691c9..2086d3b10 100644 --- a/core/src/apresolve.rs +++ b/core/src/apresolve.rs @@ -32,7 +32,7 @@ cfg_if! { let response = if let Some(url) = proxy { Client::builder() - .build(ProxyTunnel::new(url)?) + .build(ProxyTunnel::new(&url.socket_addrs(|| None)?[..])?) .request(req) .await? } else { diff --git a/core/src/connection/mod.rs b/core/src/connection/mod.rs index a07f9a2de..b715d3578 100644 --- a/core/src/connection/mod.rs +++ b/core/src/connection/mod.rs @@ -76,8 +76,8 @@ pub async fn connect(addr: String, proxy: &Option) -> io::Result .next() .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Missing port"))?; - let socket_addr = proxy.to_socket_addrs().and_then(|mut iter| { - iter.next().ok_or_else(|| { + let socket_addr = proxy.socket_addrs(|| None).and_then(|addrs| { + addrs.into_iter().next().ok_or_else(|| { io::Error::new( io::ErrorKind::NotFound, "Can't resolve proxy server address", From 6a33eb4efa72f2062af9153a4fb0a75ac40e2ab3 Mon Sep 17 00:00:00 2001 From: Evan Cameron Date: Sun, 28 Feb 2021 21:37:22 -0500 Subject: [PATCH 53/75] minor cleanup --- audio/src/fetch.rs | 59 +++++++++--------------- audio/src/lewton_decoder.rs | 10 ++-- audio/src/lib.rs | 6 +-- audio/src/passthrough_decoder.rs | 14 +++--- audio/src/range_set.rs | 23 ++++----- connect/src/discovery.rs | 23 ++++----- core/src/apresolve.rs | 4 +- core/src/authentication.rs | 8 ++-- core/src/channel.rs | 6 +-- core/src/diffie_hellman.rs | 4 +- core/src/mercury/mod.rs | 44 +++++++++--------- core/src/mercury/sender.rs | 4 +- core/src/session.rs | 9 +--- core/src/spotify_id.rs | 8 ++-- core/tests/connect.rs | 59 ++++++++++++------------ metadata/src/lib.rs | 2 +- playback/src/audio_backend/gstreamer.rs | 8 ++-- playback/src/audio_backend/jackaudio.rs | 2 +- playback/src/audio_backend/mod.rs | 2 +- playback/src/audio_backend/pulseaudio.rs | 4 +- playback/src/audio_backend/rodio.rs | 1 - playback/src/audio_backend/sdl.rs | 2 +- playback/src/audio_backend/subprocess.rs | 4 +- playback/src/mixer/alsamixer.rs | 15 +++--- playback/src/player.rs | 24 +++------- src/main.rs | 21 ++++----- src/player_event_handler.rs | 6 +-- 27 files changed, 166 insertions(+), 206 deletions(-) diff --git a/audio/src/fetch.rs b/audio/src/fetch.rs index ccbb89892..5fdf9e74f 100644 --- a/audio/src/fetch.rs +++ b/audio/src/fetch.rs @@ -138,19 +138,19 @@ impl StreamLoaderController { }) } - fn send_stream_loader_command(&mut self, command: StreamLoaderCommand) { - if let Some(ref mut channel) = self.channel_tx { + fn send_stream_loader_command(&self, command: StreamLoaderCommand) { + if let Some(ref channel) = self.channel_tx { // ignore the error in case the channel has been closed already. let _ = channel.send(command); } } - pub fn fetch(&mut self, range: Range) { + pub fn fetch(&self, range: Range) { // signal the stream loader to fetch a range of the file self.send_stream_loader_command(StreamLoaderCommand::Fetch(range)); } - pub fn fetch_blocking(&mut self, mut range: Range) { + pub fn fetch_blocking(&self, mut range: Range) { // signal the stream loader to tech a range of the file and block until it is loaded. // ensure the range is within the file's bounds. @@ -182,47 +182,43 @@ impl StreamLoaderController { { // For some reason, the requested range is neither downloaded nor requested. // This could be due to a network error. Request it again. - // We can't use self.fetch here because self can't be borrowed mutably, so we access the channel directly. - if let Some(ref mut channel) = self.channel_tx { - // ignore the error in case the channel has been closed already. - let _ = channel.send(StreamLoaderCommand::Fetch(range)); - } + self.fetch(range); } } } } - pub fn fetch_next(&mut self, length: usize) { + pub fn fetch_next(&self, length: usize) { if let Some(ref shared) = self.stream_shared { let range = Range { start: shared.read_position.load(atomic::Ordering::Relaxed), - length: length, + length, }; self.fetch(range) } } - pub fn fetch_next_blocking(&mut self, length: usize) { + pub fn fetch_next_blocking(&self, length: usize) { if let Some(ref shared) = self.stream_shared { let range = Range { start: shared.read_position.load(atomic::Ordering::Relaxed), - length: length, + length, }; self.fetch_blocking(range); } } - pub fn set_random_access_mode(&mut self) { + pub fn set_random_access_mode(&self) { // optimise download strategy for random access self.send_stream_loader_command(StreamLoaderCommand::RandomAccessMode()); } - pub fn set_stream_mode(&mut self) { + pub fn set_stream_mode(&self) { // optimise download strategy for streaming self.send_stream_loader_command(StreamLoaderCommand::StreamMode()); } - pub fn close(&mut self) { + pub fn close(&self) { // terminate stream loading and don't load any more data for this file. self.send_stream_loader_command(StreamLoaderCommand::Close()); } @@ -230,11 +226,8 @@ impl StreamLoaderController { pub struct AudioFileStreaming { read_file: fs::File, - position: u64, - stream_loader_command_tx: mpsc::UnboundedSender, - shared: Arc, } @@ -332,10 +325,7 @@ impl AudioFile { } pub fn is_cached(&self) -> bool { - match self { - AudioFile::Cached { .. } => true, - _ => false, - } + matches!(self, AudioFile::Cached { .. }) } } @@ -359,7 +349,7 @@ impl AudioFileStreaming { let size = BigEndian::read_u32(&data) as usize * 4; let shared = Arc::new(AudioFileShared { - file_id: file_id, + file_id, file_size: size, stream_data_rate: streaming_data_rate, cond: Condvar::new(), @@ -396,11 +386,10 @@ impl AudioFileStreaming { session.spawn(fetcher); Ok(AudioFileStreaming { - read_file: read_file, + read_file, position: 0, - //seek: seek_tx, - stream_loader_command_tx: stream_loader_command_tx, - shared: shared, + stream_loader_command_tx, + shared, }) } } @@ -486,7 +475,7 @@ async fn audio_file_fetch_receive_data( let data_size = data.len(); let _ = file_data_tx.send(ReceivedData::Data(PartialFileData { offset: data_offset, - data: data, + data, })); data_offset += data_size; if request_length < data_size { @@ -728,14 +717,12 @@ impl AudioFileFetch { )); AudioFileFetch { - session: session, - shared: shared, + session, + shared, output: Some(output), - - file_data_tx: file_data_tx, - file_data_rx: file_data_rx, - - stream_loader_command_rx: stream_loader_command_rx, + file_data_tx, + file_data_rx, + stream_loader_command_rx, complete_tx: Some(complete_tx), network_response_times_ms: Vec::new(), } diff --git a/audio/src/lewton_decoder.rs b/audio/src/lewton_decoder.rs index 086ea57e0..698cc64d0 100644 --- a/audio/src/lewton_decoder.rs +++ b/audio/src/lewton_decoder.rs @@ -1,6 +1,7 @@ +use super::{AudioDecoder, AudioError, AudioPacket}; + use lewton::inside_ogg::OggStreamReader; -use super::{AudioDecoder, AudioError, AudioPacket}; use std::error; use std::fmt; use std::io::{Read, Seek}; @@ -24,16 +25,15 @@ where fn seek(&mut self, ms: i64) -> Result<(), AudioError> { let absgp = ms * 44100 / 1000; match self.0.seek_absgp_pg(absgp as u64) { - Ok(_) => return Ok(()), - Err(err) => return Err(AudioError::VorbisError(err.into())), + Ok(_) => Ok(()), + Err(err) => Err(AudioError::VorbisError(err.into())), } } fn next_packet(&mut self) -> Result, AudioError> { use lewton::audio::AudioReadError::AudioIsHeader; use lewton::OggReadError::NoCapturePatternFound; - use lewton::VorbisError::BadAudio; - use lewton::VorbisError::OggError; + use lewton::VorbisError::{BadAudio, OggError}; loop { match self.0.read_dec_packet_itl() { Ok(Some(packet)) => return Ok(Some(AudioPacket::Samples(packet))), diff --git a/audio/src/lib.rs b/audio/src/lib.rs index 099fb4a82..80f1097d5 100644 --- a/audio/src/lib.rs +++ b/audio/src/lib.rs @@ -1,4 +1,4 @@ -#![allow(clippy::unused_io_amount)] +#![allow(clippy::unused_io_amount, clippy::too_many_arguments)] #[macro_use] extern crate log; @@ -85,13 +85,13 @@ impl fmt::Display for AudioError { impl From for AudioError { fn from(err: VorbisError) -> AudioError { - AudioError::VorbisError(VorbisError::from(err)) + AudioError::VorbisError(err) } } impl From for AudioError { fn from(err: PassthroughError) -> AudioError { - AudioError::PassthroughError(PassthroughError::from(err)) + AudioError::PassthroughError(err) } } diff --git a/audio/src/passthrough_decoder.rs b/audio/src/passthrough_decoder.rs index 3a011011d..25802e4bc 100644 --- a/audio/src/passthrough_decoder.rs +++ b/audio/src/passthrough_decoder.rs @@ -27,7 +27,7 @@ fn write_headers( // remove un-needed packets rdr.delete_unread_packets(); - return Ok(stream_serial); + Ok(stream_serial) } fn get_header( @@ -65,7 +65,7 @@ where ) .unwrap(); - return Ok(*stream_serial); + Ok(*stream_serial) } pub struct PassthroughDecoder { @@ -87,13 +87,13 @@ impl PassthroughDecoder { let stream_serial = write_headers(&mut rdr, &mut wtr)?; info!("Starting passthrough track with serial {}", stream_serial); - return Ok(PassthroughDecoder { + Ok(PassthroughDecoder { rdr, wtr, lastgp_page: Some(0), absgp_page: 0, stream_serial, - }); + }) } } @@ -107,8 +107,8 @@ impl AudioDecoder for PassthroughDecoder { // hard-coded to 44.1 kHz match self.rdr.seek_absgp(None, (ms * 44100 / 1000) as u64) { - Ok(_) => return Ok(()), - Err(err) => return Err(AudioError::PassthroughError(err.into())), + Ok(_) => Ok(()), + Err(err) => Err(AudioError::PassthroughError(err.into())), } } @@ -164,7 +164,7 @@ impl AudioDecoder for PassthroughDecoder { let data = self.wtr.inner_mut(); - if data.len() > 0 { + if !data.is_empty() { let result = AudioPacket::OggData(std::mem::take(data)); return Ok(Some(result)); } diff --git a/audio/src/range_set.rs b/audio/src/range_set.rs index 31ce6500e..f74058a31 100644 --- a/audio/src/range_set.rs +++ b/audio/src/range_set.rs @@ -16,14 +16,11 @@ impl fmt::Display for Range { impl Range { pub fn new(start: usize, length: usize) -> Range { - return Range { - start: start, - length: length, - }; + Range { start, length } } pub fn end(&self) -> usize { - return self.start + self.length; + self.start + self.length } } @@ -50,7 +47,7 @@ impl RangeSet { } pub fn is_empty(&self) -> bool { - return self.ranges.is_empty(); + self.ranges.is_empty() } pub fn len(&self) -> usize { @@ -58,11 +55,11 @@ impl RangeSet { } pub fn get_range(&self, index: usize) -> Range { - return self.ranges[index].clone(); + self.ranges[index] } pub fn iter(&self) -> Iter { - return self.ranges.iter(); + self.ranges.iter() } pub fn contains(&self, value: usize) -> bool { @@ -73,7 +70,7 @@ impl RangeSet { return true; } } - return false; + false } pub fn contained_length_from_value(&self, value: usize) -> usize { @@ -84,7 +81,7 @@ impl RangeSet { return range.end() - value; } } - return 0; + 0 } #[allow(dead_code)] @@ -144,7 +141,7 @@ impl RangeSet { pub fn union(&self, other: &RangeSet) -> RangeSet { let mut result = self.clone(); result.add_range_set(other); - return result; + result } pub fn subtract_range(&mut self, range: &Range) { @@ -204,7 +201,7 @@ impl RangeSet { pub fn minus(&self, other: &RangeSet) -> RangeSet { let mut result = self.clone(); result.subtract_range_set(other); - return result; + result } pub fn intersection(&self, other: &RangeSet) -> RangeSet { @@ -240,6 +237,6 @@ impl RangeSet { } } - return result; + result } } diff --git a/connect/src/discovery.rs b/connect/src/discovery.rs index 1c94ecc8f..df4d48ebf 100644 --- a/connect/src/discovery.rs +++ b/connect/src/discovery.rs @@ -5,34 +5,31 @@ use futures_core::Stream; use hmac::{Hmac, Mac, NewMac}; use hyper::service::{make_service_fn, service_fn}; use hyper::{Body, Method, Request, Response, StatusCode}; +use num_bigint::BigUint; use serde_json::json; use sha1::{Digest, Sha1}; use tokio::sync::{mpsc, oneshot}; -use std::borrow::Cow; -use std::convert::Infallible; -use std::net::{Ipv4Addr, SocketAddr}; -use std::task::{Context, Poll}; - #[cfg(feature = "with-dns-sd")] use dns_sd::DNSService; #[cfg(not(feature = "with-dns-sd"))] use libmdns; -use num_bigint::BigUint; -use rand; -use std::collections::BTreeMap; -use std::io; -use std::pin::Pin; -use std::sync::Arc; -use url; - use librespot_core::authentication::Credentials; use librespot_core::config::ConnectConfig; use librespot_core::diffie_hellman::{DH_GENERATOR, DH_PRIME}; use librespot_core::util; +use std::borrow::Cow; +use std::collections::BTreeMap; +use std::convert::Infallible; +use std::io; +use std::net::{Ipv4Addr, SocketAddr}; +use std::pin::Pin; +use std::sync::Arc; +use std::task::{Context, Poll}; + type HmacSha1 = Hmac; #[derive(Clone)] diff --git a/core/src/apresolve.rs b/core/src/apresolve.rs index 2086d3b10..531a3e074 100644 --- a/core/src/apresolve.rs +++ b/core/src/apresolve.rs @@ -1,10 +1,10 @@ -const AP_FALLBACK: &'static str = "ap.spotify.com:443"; +const AP_FALLBACK: &str = "ap.spotify.com:443"; use url::Url; cfg_if! { if #[cfg(feature = "apresolve")] { - const APRESOLVE_ENDPOINT: &'static str = "http://apresolve.spotify.com:80"; + const APRESOLVE_ENDPOINT: &str = "http://apresolve.spotify.com:80"; use std::error::Error; diff --git a/core/src/authentication.rs b/core/src/authentication.rs index 544dda4c9..283935394 100644 --- a/core/src/authentication.rs +++ b/core/src/authentication.rs @@ -27,7 +27,7 @@ pub struct Credentials { impl Credentials { pub fn with_password(username: String, password: String) -> Credentials { Credentials { - username: username, + username, auth_type: AuthenticationType::AUTHENTICATION_USER_PASS, auth_data: password.into_bytes(), } @@ -103,9 +103,9 @@ impl Credentials { let auth_data = read_bytes(&mut cursor).unwrap(); Credentials { - username: username, - auth_type: auth_type, - auth_data: auth_data, + username, + auth_type, + auth_data, } } } diff --git a/core/src/channel.rs b/core/src/channel.rs index 54eee1841..4e73b6165 100644 --- a/core/src/channel.rs +++ b/core/src/channel.rs @@ -93,7 +93,7 @@ impl ChannelManager { } pub fn get_download_rate_estimate(&self) -> usize { - return self.lock(|inner| inner.download_rate_estimate); + self.lock(|inner| inner.download_rate_estimate) } pub(crate) fn shutdown(&self) { @@ -139,7 +139,7 @@ impl Stream for Channel { match self.state.clone() { ChannelState::Closed => panic!("Polling already terminated channel"), ChannelState::Header(mut data) => { - if data.len() == 0 { + if data.is_empty() { data = match self.recv_packet(cx) { Poll::Ready(Ok(x)) => x, Poll::Ready(Err(x)) => return Poll::Ready(Some(Err(x))), @@ -168,7 +168,7 @@ impl Stream for Channel { Poll::Ready(Err(x)) => return Poll::Ready(Some(Err(x))), Poll::Pending => return Poll::Pending, }; - if data.len() == 0 { + if data.is_empty() { self.receiver.close(); self.state = ChannelState::Closed; return Poll::Ready(None); diff --git a/core/src/diffie_hellman.rs b/core/src/diffie_hellman.rs index 358901bea..854480988 100644 --- a/core/src/diffie_hellman.rs +++ b/core/src/diffie_hellman.rs @@ -30,8 +30,8 @@ impl DHLocalKeys { let public_key = util::powm(&DH_GENERATOR, &private_key, &DH_PRIME); DHLocalKeys { - private_key: private_key, - public_key: public_key, + private_key, + public_key, } } diff --git a/core/src/mercury/mod.rs b/core/src/mercury/mod.rs index 537ff2cb8..1a68e15eb 100644 --- a/core/src/mercury/mod.rs +++ b/core/src/mercury/mod.rs @@ -211,30 +211,28 @@ impl MercuryManager { if let Some(cb) = pending.callback { let _ = cb.send(Err(MercuryError)); } - } else { - if cmd == 0xb5 { - self.lock(|inner| { - let mut found = false; - inner.subscriptions.retain(|&(ref prefix, ref sub)| { - if response.uri.starts_with(prefix) { - found = true; - - // if send fails, remove from list of subs - // TODO: send unsub message - sub.send(response.clone()).is_ok() - } else { - // URI doesn't match - true - } - }); - - if !found { - debug!("unknown subscription uri={}", response.uri); + } else if cmd == 0xb5 { + self.lock(|inner| { + let mut found = false; + inner.subscriptions.retain(|&(ref prefix, ref sub)| { + if response.uri.starts_with(prefix) { + found = true; + + // if send fails, remove from list of subs + // TODO: send unsub message + sub.send(response.clone()).is_ok() + } else { + // URI doesn't match + true } - }) - } else if let Some(cb) = pending.callback { - let _ = cb.send(Ok(response)); - } + }); + + if !found { + debug!("unknown subscription uri={}", response.uri); + } + }) + } else if let Some(cb) = pending.callback { + let _ = cb.send(Ok(response)); } } diff --git a/core/src/mercury/sender.rs b/core/src/mercury/sender.rs index e276bcf1e..383d449d2 100644 --- a/core/src/mercury/sender.rs +++ b/core/src/mercury/sender.rs @@ -12,8 +12,8 @@ impl MercurySender { // TODO: pub(super) when stable pub(crate) fn new(mercury: MercuryManager, uri: String) -> MercurySender { MercurySender { - mercury: mercury, - uri: uri, + mercury, + uri, pending: VecDeque::new(), } } diff --git a/core/src/session.rs b/core/src/session.rs index 9eaff3ed5..53bbabd8b 100644 --- a/core/src/session.rs +++ b/core/src/session.rs @@ -105,25 +105,20 @@ impl Session { debug!("new Session[{}]", session_id); let session = Session(Arc::new(SessionInternal { - config: config, + config, data: RwLock::new(SessionData { country: String::new(), canonical_username: username, invalid: false, time_delta: 0, }), - tx_connection: sender_tx, - cache: cache.map(Arc::new), - audio_key: OnceCell::new(), channel: OnceCell::new(), mercury: OnceCell::new(), - handle, - - session_id: session_id, + session_id, })); let sender_task = UnboundedReceiverStream::new(sender_rx) diff --git a/core/src/spotify_id.rs b/core/src/spotify_id.rs index 17327b478..09d109758 100644 --- a/core/src/spotify_id.rs +++ b/core/src/spotify_id.rs @@ -45,7 +45,7 @@ impl SpotifyId { const SIZE_BASE16: usize = 32; const SIZE_BASE62: usize = 22; - fn as_track(n: u128) -> SpotifyId { + fn track(n: u128) -> SpotifyId { SpotifyId { id: n, audio_type: SpotifyAudioType::Track, @@ -71,7 +71,7 @@ impl SpotifyId { dst += p; } - Ok(SpotifyId::as_track(dst)) + Ok(SpotifyId::track(dst)) } /// Parses a base62 encoded [Spotify ID] into a `SpotifyId`. @@ -94,7 +94,7 @@ impl SpotifyId { dst += p; } - Ok(SpotifyId::as_track(dst)) + Ok(SpotifyId::track(dst)) } /// Creates a `SpotifyId` from a copy of `SpotifyId::SIZE` (16) bytes in big-endian order. @@ -102,7 +102,7 @@ impl SpotifyId { /// The resulting `SpotifyId` will default to a `SpotifyAudioType::TRACK`. pub fn from_raw(src: &[u8]) -> Result { match src.try_into() { - Ok(dst) => Ok(SpotifyId::as_track(u128::from_be_bytes(dst))), + Ok(dst) => Ok(SpotifyId::track(u128::from_be_bytes(dst))), Err(_) => Err(SpotifyIdError), } } diff --git a/core/tests/connect.rs b/core/tests/connect.rs index 4ea2a1fe5..b7bc29f81 100644 --- a/core/tests/connect.rs +++ b/core/tests/connect.rs @@ -1,33 +1,34 @@ use librespot_core::*; -#[cfg(test)] -mod tests { - use super::*; - // Test AP Resolve - use apresolve::apresolve_or_fallback; - #[tokio::test] - async fn test_ap_resolve() { - env_logger::init(); - let ap = apresolve_or_fallback(&None, &None).await; - println!("AP: {:?}", ap); - } +// TODO: test is broken +// #[cfg(test)] +// mod tests { +// use super::*; +// // Test AP Resolve +// use apresolve::apresolve_or_fallback; +// #[tokio::test] +// async fn test_ap_resolve() { +// env_logger::init(); +// let ap = apresolve_or_fallback(&None, &None).await; +// println!("AP: {:?}", ap); +// } - // Test connect - use authentication::Credentials; - use config::SessionConfig; - #[tokio::test] - async fn test_connection() -> Result<(), Box> { - println!("Running connection test"); - let ap = apresolve_or_fallback(&None, &None).await; - let credentials = Credentials::with_password(String::from("test"), String::from("test")); - let session_config = SessionConfig::default(); - let proxy = None; +// // Test connect +// use authentication::Credentials; +// use config::SessionConfig; +// #[tokio::test] +// async fn test_connection() -> Result<(), Box> { +// println!("Running connection test"); +// let ap = apresolve_or_fallback(&None, &None).await; +// let credentials = Credentials::with_password(String::from("test"), String::from("test")); +// let session_config = SessionConfig::default(); +// let proxy = None; - println!("Connecting to AP \"{}\"", ap); - let mut connection = connection::connect(ap, &proxy).await?; - let rc = connection::authenticate(&mut connection, credentials, &session_config.device_id) - .await?; - println!("Authenticated as \"{}\"", rc.username); - Ok(()) - } -} +// println!("Connecting to AP \"{}\"", ap); +// let mut connection = connection::connect(ap, &proxy).await?; +// let rc = connection::authenticate(&mut connection, credentials, &session_config.device_id) +// .await?; +// println!("Authenticated as \"{}\"", rc.username); +// Ok(()) +// } +// } diff --git a/metadata/src/lib.rs b/metadata/src/lib.rs index 8faa027e1..75c07f83f 100644 --- a/metadata/src/lib.rs +++ b/metadata/src/lib.rs @@ -292,7 +292,7 @@ impl Metadata for Playlist { .get_items() .iter() .map(|item| { - let uri_split = item.get_uri().split(":"); + let uri_split = item.get_uri().split(':'); let uri_parts: Vec<&str> = uri_split.collect(); SpotifyId::from_base62(uri_parts[2]).unwrap() }) diff --git a/playback/src/audio_backend/gstreamer.rs b/playback/src/audio_backend/gstreamer.rs index 6be6dd722..4678bfb07 100644 --- a/playback/src/audio_backend/gstreamer.rs +++ b/playback/src/audio_backend/gstreamer.rs @@ -2,9 +2,10 @@ use super::{Open, Sink}; use crate::audio::AudioPacket; use gst::prelude::*; use gst::*; +use zerocopy::*; + use std::sync::mpsc::{sync_channel, SyncSender}; use std::{io, thread}; -use zerocopy::*; #[allow(dead_code)] pub struct GstreamerSink { @@ -91,10 +92,7 @@ impl Open for GstreamerSink { .set_state(gst::State::Playing) .expect("Unable to set the pipeline to the `Playing` state"); - GstreamerSink { - tx: tx, - pipeline: pipeline, - } + GstreamerSink { tx, pipeline } } } diff --git a/playback/src/audio_backend/jackaudio.rs b/playback/src/audio_backend/jackaudio.rs index 4699c1824..e659d54f9 100644 --- a/playback/src/audio_backend/jackaudio.rs +++ b/playback/src/audio_backend/jackaudio.rs @@ -60,7 +60,7 @@ impl Open for JackSink { JackSink { send: tx, - active_client: active_client, + active_client, } } } diff --git a/playback/src/audio_backend/mod.rs b/playback/src/audio_backend/mod.rs index 214ede8c3..c816a6d66 100644 --- a/playback/src/audio_backend/mod.rs +++ b/playback/src/audio_backend/mod.rs @@ -56,7 +56,7 @@ use self::pipe::StdoutSink; mod subprocess; use self::subprocess::SubprocessSink; -pub const BACKENDS: &'static [(&'static str, SinkBuilder)] = &[ +pub const BACKENDS: &[(&str, SinkBuilder)] = &[ #[cfg(feature = "alsa-backend")] ("alsa", mk_sink::), #[cfg(feature = "portaudio-backend")] diff --git a/playback/src/audio_backend/pulseaudio.rs b/playback/src/audio_backend/pulseaudio.rs index 11ea026ae..bc2be9094 100644 --- a/playback/src/audio_backend/pulseaudio.rs +++ b/playback/src/audio_backend/pulseaudio.rs @@ -26,8 +26,8 @@ impl Open for PulseAudioSink { PulseAudioSink { s: None, - ss: ss, - device: device, + ss, + device, } } } diff --git a/playback/src/audio_backend/rodio.rs b/playback/src/audio_backend/rodio.rs index 56e19b61d..338dfbbfe 100644 --- a/playback/src/audio_backend/rodio.rs +++ b/playback/src/audio_backend/rodio.rs @@ -43,7 +43,6 @@ pub enum RodioError { pub struct RodioSink { rodio_sink: rodio::Sink, - // will produce a TryRecvError on the receiver side when it is dropped. _close_tx: mpsc::SyncSender, } diff --git a/playback/src/audio_backend/sdl.rs b/playback/src/audio_backend/sdl.rs index 27d650f9e..47cd225c6 100644 --- a/playback/src/audio_backend/sdl.rs +++ b/playback/src/audio_backend/sdl.rs @@ -29,7 +29,7 @@ impl Open for SdlSink { .open_queue(None, &desired_spec) .expect("Could not open SDL audio device"); - SdlSink { queue: queue } + SdlSink { queue } } } diff --git a/playback/src/audio_backend/subprocess.rs b/playback/src/audio_backend/subprocess.rs index 0dd25638d..9b24e219c 100644 --- a/playback/src/audio_backend/subprocess.rs +++ b/playback/src/audio_backend/subprocess.rs @@ -1,6 +1,8 @@ use super::{Open, Sink}; use crate::audio::AudioPacket; + use shell_words::split; + use std::io::{self, Write}; use std::mem; use std::process::{Child, Command, Stdio}; @@ -15,7 +17,7 @@ impl Open for SubprocessSink { fn open(shell_command: Option) -> SubprocessSink { if let Some(shell_command) = shell_command { SubprocessSink { - shell_command: shell_command, + shell_command, child: None, } } else { diff --git a/playback/src/mixer/alsamixer.rs b/playback/src/mixer/alsamixer.rs index 1e00cc846..d9dbe311f 100644 --- a/playback/src/mixer/alsamixer.rs +++ b/playback/src/mixer/alsamixer.rs @@ -1,10 +1,7 @@ use super::AudioFilter; use super::{Mixer, MixerConfig}; -use std; use std::error::Error; -use alsa; - const SND_CTL_TLV_DB_GAIN_MUTE: i64 = -9999999; #[derive(Clone)] @@ -72,14 +69,14 @@ impl AlsaMixer { } Ok(AlsaMixer { - config: config, + config, params: AlsaMixerVolumeParams { - min: min, - max: max, + min, + max, range: (max - min) as f64, - min_db: min_db, - max_db: max_db, - has_switch: has_switch, + min_db, + max_db, + has_switch, }, }) } diff --git a/playback/src/player.rs b/playback/src/player.rs index 9b2c7125b..7c200b2ac 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -252,8 +252,8 @@ impl Player { debug!("new Player[{}]", session.session_id()); let internal = PlayerInternal { - session: session, - config: config, + session, + config, commands: cmd_rx, state: PlayerState::Stopped, @@ -261,7 +261,7 @@ impl Player { sink: sink_builder(), sink_status: SinkStatus::Closed, sink_event_callback: None, - audio_filter: audio_filter, + audio_filter, event_senders: [event_sender].to_vec(), }; @@ -432,18 +432,12 @@ impl PlayerState { #[allow(dead_code)] fn is_stopped(&self) -> bool { use self::PlayerState::*; - match *self { - Stopped => true, - _ => false, - } + matches!(self, Stopped) } fn is_loading(&self) -> bool { use self::PlayerState::*; - match *self { - Loading { .. } => true, - _ => false, - } + matches!(self, Loading { .. }) } fn decoder(&mut self) -> Option<&mut Decoder> { @@ -697,7 +691,7 @@ impl PlayerTrackLoader { }; let is_cached = encrypted_file.is_cached(); - let mut stream_loader_controller = encrypted_file.get_stream_loader_controller(); + let stream_loader_controller = encrypted_file.get_stream_loader_controller(); if play_from_beginning { // No need to seek -> we stream from the beginning @@ -908,11 +902,7 @@ impl Future for PlayerInternal { .as_millis() as i64 - stream_position_millis as i64; - if lag > 1000 { - true - } else { - false - } + lag > 1000 } }; if notify_about_position { diff --git a/src/main.rs b/src/main.rs index 5de83de14..7bddfaa5f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,33 +2,32 @@ use futures_util::{future, FutureExt, StreamExt}; use librespot_playback::player::PlayerEvent; use log::{error, info, warn}; use sha1::{Digest, Sha1}; -use std::path::Path; -use std::process::exit; -use std::str::FromStr; -use std::{env, time::Instant}; -use std::{ - io::{stderr, Write}, - pin::Pin, -}; use tokio::sync::mpsc::UnboundedReceiver; use url::Url; +use librespot::connect::spirc::Spirc; use librespot::core::authentication::Credentials; use librespot::core::cache::Cache; use librespot::core::config::{ConnectConfig, DeviceType, SessionConfig, VolumeCtrl}; use librespot::core::session::Session; use librespot::core::version; - -use librespot::connect::spirc::Spirc; use librespot::playback::audio_backend::{self, Sink, BACKENDS}; use librespot::playback::config::{Bitrate, NormalisationType, PlayerConfig}; use librespot::playback::mixer::{self, Mixer, MixerConfig}; use librespot::playback::player::Player; mod player_event_handler; - use player_event_handler::{emit_sink_event, run_program_on_events}; +use std::path::Path; +use std::process::exit; +use std::str::FromStr; +use std::{env, time::Instant}; +use std::{ + io::{stderr, Write}, + pin::Pin, +}; + fn device_id(name: &str) -> String { hex::encode(Sha1::digest(name.as_bytes())) } diff --git a/src/player_event_handler.rs b/src/player_event_handler.rs index 361e6b1ab..4c75128cc 100644 --- a/src/player_event_handler.rs +++ b/src/player_event_handler.rs @@ -1,12 +1,12 @@ use librespot::playback::player::PlayerEvent; +use librespot::playback::player::SinkStatus; use log::info; +use tokio::process::{Child as AsyncChild, Command as AsyncCommand}; + use std::collections::HashMap; use std::io; use std::process::{Command, ExitStatus}; -use librespot::playback::player::SinkStatus; -use tokio::process::{Child as AsyncChild, Command as AsyncCommand}; - pub fn run_program_on_events(event: PlayerEvent, onevent: &str) -> Option> { let mut env_vars = HashMap::new(); match event { From 3388508141bbbfe97f978381e2878bd898ceaa6c Mon Sep 17 00:00:00 2001 From: Evan Cameron Date: Sun, 28 Feb 2021 22:09:46 -0500 Subject: [PATCH 54/75] use current_thread --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 7bddfaa5f..6f04ac1fe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -452,7 +452,7 @@ fn setup(args: &[String]) -> Setup { } } -#[tokio::main] +#[tokio::main(flavor = "current_thread")] async fn main() { if env::var("RUST_BACKTRACE").is_err() { env::set_var("RUST_BACKTRACE", "full") From 5616004dbec3836b9382494312766eda6c3186de Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Wed, 10 Mar 2021 22:32:24 +0100 Subject: [PATCH 55/75] Fix many clippy lints ...and other small improvements --- README.md | 2 +- connect/src/discovery.rs | 5 +---- connect/src/spirc.rs | 18 ++++++++++-------- core/src/channel.rs | 9 +++++---- core/src/connection/handshake.rs | 8 ++++---- playback/src/mixer/mod.rs | 4 +++- playback/src/player.rs | 28 +++++++++++++--------------- src/main.rs | 18 ++++++------------ 8 files changed, 43 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index 7102c28a0..33b2b76e2 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ ALSA PortAudio PulseAudio JACK -JACK over Rodio +JACK over Rodio SDL Pipe ``` diff --git a/connect/src/discovery.rs b/connect/src/discovery.rs index df4d48ebf..e03b15950 100644 --- a/connect/src/discovery.rs +++ b/connect/src/discovery.rs @@ -13,9 +13,6 @@ use tokio::sync::{mpsc, oneshot}; #[cfg(feature = "with-dns-sd")] use dns_sd::DNSService; -#[cfg(not(feature = "with-dns-sd"))] -use libmdns; - use librespot_core::authentication::Credentials; use librespot_core::config::ConnectConfig; use librespot_core::diffie_hellman::{DH_GENERATOR, DH_PRIME}; @@ -127,7 +124,7 @@ impl Discovery { let mut h = HmacSha1::new_varkey(&checksum_key).expect("HMAC can take key of any size"); h.update(encrypted); - if let Err(_) = h.verify(cksum) { + if h.verify(cksum).is_err() { warn!("Login error for user {:?}: MAC mismatch", username); let result = json!({ "status": 102, diff --git a/connect/src/spirc.rs b/connect/src/spirc.rs index 5afefe7f9..6869dd8bc 100644 --- a/connect/src/spirc.rs +++ b/connect/src/spirc.rs @@ -426,8 +426,8 @@ impl SpircTask { Ok(dur) => dur, Err(err) => err.duration(), }; - (dur.as_secs() as i64 + self.session.time_delta()) * 1000 - + (dur.subsec_nanos() / 1000_000) as i64 + + dur.as_millis() as i64 + 1000 * self.session.time_delta() } fn ensure_mixer_started(&mut self) { @@ -512,7 +512,9 @@ impl SpircTask { SpircCommand::Shutdown => { CommandSender::new(self, MessageType::kMessageTypeGoodbye).send(); self.shutdown = true; - self.commands.as_mut().map(|rx| rx.close()); + if let Some(rx) = self.commands.as_mut() { + rx.close() + } } } } @@ -620,7 +622,7 @@ impl SpircTask { ); if frame.get_ident() == self.ident - || (frame.get_recipient().len() > 0 && !frame.get_recipient().contains(&self.ident)) + || (!frame.get_recipient().is_empty() && !frame.get_recipient().contains(&self.ident)) { return; } @@ -639,7 +641,7 @@ impl SpircTask { self.update_tracks(&frame); - if self.state.get_track().len() > 0 { + if !self.state.get_track().is_empty() { let start_playing = frame.get_state().get_status() == PlayStatus::kPlayStatusPlay; self.load_track(start_playing, frame.get_state().get_position_ms()); @@ -862,7 +864,7 @@ impl SpircTask { fn preview_next_track(&mut self) -> Option { self.get_track_id_to_play_from_playlist(self.state.get_playing_track_index() + 1) - .and_then(|(track_id, _)| Some(track_id)) + .map(|(track_id, _)| track_id) } fn handle_preload_next_track(&mut self) { @@ -981,7 +983,7 @@ impl SpircTask { }; // Reinsert queued tracks after the new playing track. let mut pos = (new_index + 1) as usize; - for track in queue_tracks.into_iter() { + for track in queue_tracks { self.state.mut_track().insert(pos, track); pos += 1; } @@ -1120,7 +1122,7 @@ impl SpircTask { } self.state.set_playing_track_index(index); - self.state.set_track(tracks.into_iter().cloned().collect()); + self.state.set_track(tracks.iter().cloned().collect()); self.state.set_context_uri(context_uri); // has_shuffle/repeat seem to always be true in these replace msgs, // but to replicate the behaviour of the Android client we have to diff --git a/core/src/channel.rs b/core/src/channel.rs index 4e73b6165..387b3966f 100644 --- a/core/src/channel.rs +++ b/core/src/channel.rs @@ -192,11 +192,12 @@ impl Stream for ChannelData { }; loop { - let x = match channel.poll_next_unpin(cx) { + let event = match channel.poll_next_unpin(cx) { Poll::Ready(x) => x.transpose()?, Poll::Pending => return Poll::Pending, }; - match x { + + match event { Some(ChannelEvent::Header(..)) => (), Some(ChannelEvent::Data(data)) => return Poll::Ready(Some(Ok(data))), None => return Poll::Ready(None), @@ -214,12 +215,12 @@ impl Stream for ChannelHeaders { Poll::Pending => return Poll::Pending, }; - let x = match channel.poll_next_unpin(cx) { + let event = match channel.poll_next_unpin(cx) { Poll::Ready(x) => x.transpose()?, Poll::Pending => return Poll::Pending, }; - match x { + match event { Some(ChannelEvent::Header(id, data)) => Poll::Ready(Some(Ok((id, data)))), Some(ChannelEvent::Data(..)) | None => Poll::Ready(None), } diff --git a/core/src/connection/handshake.rs b/core/src/connection/handshake.rs index 02d771340..67a786eee 100644 --- a/core/src/connection/handshake.rs +++ b/core/src/connection/handshake.rs @@ -104,11 +104,11 @@ where Ok(message) } -async fn read_into_accumulator<'a, T: AsyncRead + Unpin>( - connection: &mut T, +async fn read_into_accumulator<'a, 'b, T: AsyncRead + Unpin>( + connection: &'a mut T, size: usize, - acc: &'a mut Vec, -) -> io::Result<&'a mut [u8]> { + acc: &'b mut Vec, +) -> io::Result<&'b mut [u8]> { let offset = acc.len(); acc.resize(offset + size, 0); diff --git a/playback/src/mixer/mod.rs b/playback/src/mixer/mod.rs index 325c1e18d..9d9a81755 100644 --- a/playback/src/mixer/mod.rs +++ b/playback/src/mixer/mod.rs @@ -42,11 +42,13 @@ impl Default for MixerConfig { pub mod softmixer; use self::softmixer::SoftMixer; +type MixerFn = fn(Option) -> Box; + fn mk_sink(device: Option) -> Box { Box::new(M::open(device)) } -pub fn find>(name: Option) -> Option) -> Box> { +pub fn find>(name: Option) -> Option { match name.as_ref().map(AsRef::as_ref) { None | Some("softvol") => Some(mk_sink::), #[cfg(feature = "alsa-backend")] diff --git a/playback/src/player.rs b/playback/src/player.rs index 7c200b2ac..6c9e516d1 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -196,13 +196,12 @@ struct NormalisationData { impl NormalisationData { fn parse_from_file(mut file: T) -> io::Result { const SPOTIFY_NORMALIZATION_HEADER_START_OFFSET: u64 = 144; - file.seek(SeekFrom::Start(SPOTIFY_NORMALIZATION_HEADER_START_OFFSET)) - .unwrap(); + file.seek(SeekFrom::Start(SPOTIFY_NORMALIZATION_HEADER_START_OFFSET))?; - let track_gain_db = file.read_f32::().unwrap(); - let track_peak = file.read_f32::().unwrap(); - let album_gain_db = file.read_f32::().unwrap(); - let album_peak = file.read_f32::().unwrap(); + let track_gain_db = file.read_f32::()?; + let track_peak = file.read_f32::()?; + let album_gain_db = file.read_f32::()?; + let album_peak = file.read_f32::()?; let r = NormalisationData { track_gain_db: track_gain_db, @@ -889,8 +888,7 @@ impl Future for PlayerInternal { if !passthrough { if let Some(ref packet) = packet { - *stream_position_pcm = - *stream_position_pcm + (packet.samples().len() / 2) as u64; + *stream_position_pcm += (packet.samples().len() / 2) as u64; let stream_position_millis = Self::position_pcm_to_ms(*stream_position_pcm); @@ -1111,7 +1109,9 @@ impl PlayerInternal { editor.modify_stream(data) } - if self.config.normalisation && normalisation_factor != 1.0 { + if self.config.normalisation + && f32::abs(normalisation_factor - 1.0) > f32::EPSILON + { for x in data.iter_mut() { *x = (*x as f32 * normalisation_factor) as i16; } @@ -1598,12 +1598,10 @@ impl PlayerInternal { let (result_tx, result_rx) = oneshot::channel(); std::thread::spawn(move || { - futures_executor::block_on(loader.load_track(spotify_id, position_ms)).and_then( - move |data| { - let _ = result_tx.send(data); - Some(()) - }, - ); + let data = futures_executor::block_on(loader.load_track(spotify_id, position_ms)); + if let Some(data) = data { + let _ = result_tx.send(data); + } }); result_rx.map_err(|_| ()) diff --git a/src/main.rs b/src/main.rs index 6f04ac1fe..ff9e564c4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -236,13 +236,7 @@ fn setup(args: &[String]) -> Setup { let matches = match opts.parse(&args[1..]) { Ok(m) => m, Err(f) => { - writeln!( - stderr(), - "error: {}\n{}", - f.to_string(), - usage(&args[0], &opts) - ) - .unwrap(); + eprintln!("error: {}\n{}", f.to_string(), usage(&args[0], &opts)); exit(1); } }; @@ -360,7 +354,7 @@ fn setup(args: &[String]) -> Setup { SessionConfig { user_agent: version::version_string(), device_id: device_id, - proxy: matches.opt_str("proxy").or(std::env::var("http_proxy").ok()).map( + proxy: matches.opt_str("proxy").or_else(|| std::env::var("http_proxy").ok()).map( |s| { match Url::parse(&s) { Ok(url) => { @@ -390,14 +384,14 @@ fn setup(args: &[String]) -> Setup { .opt_str("b") .as_ref() .map(|bitrate| Bitrate::from_str(bitrate).expect("Invalid bitrate")) - .unwrap_or(Bitrate::default()); + .unwrap_or_default(); let gain_type = matches .opt_str("normalisation-gain-type") .as_ref() .map(|gain_type| { NormalisationType::from_str(gain_type).expect("Invalid normalisation type") }) - .unwrap_or(NormalisationType::default()); + .unwrap_or_default(); PlayerConfig { bitrate: bitrate, gapless: !matches.opt_present("disable-gapless"), @@ -416,13 +410,13 @@ fn setup(args: &[String]) -> Setup { .opt_str("device-type") .as_ref() .map(|device_type| DeviceType::from_str(device_type).expect("Invalid device type")) - .unwrap_or(DeviceType::default()); + .unwrap_or_default(); let volume_ctrl = matches .opt_str("volume-ctrl") .as_ref() .map(|volume_ctrl| VolumeCtrl::from_str(volume_ctrl).expect("Invalid volume ctrl type")) - .unwrap_or(VolumeCtrl::default()); + .unwrap_or_default(); ConnectConfig { name: name, From 059b9029ded1ac7d08efdef3ec1e841d33b0b5ef Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Wed, 10 Mar 2021 22:39:01 +0100 Subject: [PATCH 56/75] Remove redundant field names --- connect/src/discovery.rs | 10 +++++----- connect/src/spirc.rs | 19 ++++++++----------- metadata/src/lib.rs | 27 +++++++++++++-------------- playback/src/player.rs | 23 ++++++++++------------- src/main.rs | 32 ++++++++++++++++---------------- 5 files changed, 52 insertions(+), 59 deletions(-) diff --git a/connect/src/discovery.rs b/connect/src/discovery.rs index e03b15950..7bb36a200 100644 --- a/connect/src/discovery.rs +++ b/connect/src/discovery.rs @@ -51,11 +51,11 @@ impl Discovery { let public_key = util::powm(&DH_GENERATOR, &private_key, &DH_PRIME); let discovery = Discovery(Arc::new(DiscoveryInner { - config: config, - device_id: device_id, - private_key: private_key, - public_key: public_key, - tx: tx, + config, + device_id, + private_key, + public_key, + tx, })); (discovery, rx) diff --git a/connect/src/spirc.rs b/connect/src/spirc.rs index 6869dd8bc..f111e5417 100644 --- a/connect/src/spirc.rs +++ b/connect/src/spirc.rs @@ -287,27 +287,27 @@ impl Spirc { let player_events = player.get_player_event_channel(); let mut task = SpircTask { - player: player, - mixer: mixer, + player, + mixer, config: task_config, sequence: SeqGenerator::new(1), - ident: ident, + ident, - device: device, + device, state: initial_state(), play_request_id: None, mixer_started: false, play_status: SpircPlayStatus::Stopped, - subscription: subscription, - sender: sender, + subscription, + sender, commands: Some(cmd_rx), player_events: Some(player_events), shutdown: false, - session: session, + session, context_fut: Box::pin(future::pending()), autoplay_fut: Box::pin(future::pending()), @@ -1293,10 +1293,7 @@ impl<'a> CommandSender<'a> { frame.set_typ(cmd); frame.set_device_state(spirc.device.clone()); frame.set_state_update_id(spirc.now_ms()); - CommandSender { - spirc: spirc, - frame: frame, - } + CommandSender { spirc, frame } } fn recipient(mut self, recipient: &'a str) -> CommandSender { diff --git a/metadata/src/lib.rs b/metadata/src/lib.rs index 75c07f83f..2c982ec7d 100644 --- a/metadata/src/lib.rs +++ b/metadata/src/lib.rs @@ -1,5 +1,4 @@ #![allow(clippy::unused_io_amount)] -#![allow(clippy::redundant_field_names)] #[macro_use] extern crate log; @@ -85,7 +84,7 @@ impl AudioFiles for Track { async fn get_audio_item(session: &Session, id: SpotifyId) -> Result { let item = Self::get(session, id).await?; Ok(AudioItem { - id: id, + id, uri: format!("spotify:track:{}", id.to_base62()), files: item.files, name: item.name, @@ -102,7 +101,7 @@ impl AudioFiles for Episode { let item = Self::get(session, id).await?; Ok(AudioItem { - id: id, + id, uri: format!("spotify:episode:{}", id.to_base62()), files: item.files, name: item.name, @@ -222,8 +221,8 @@ impl Metadata for Track { name: msg.get_name().to_owned(), duration: msg.get_duration(), album: SpotifyId::from_raw(msg.get_album().get_gid()).unwrap(), - artists: artists, - files: files, + artists, + files, alternatives: msg .get_alternative() .iter() @@ -272,9 +271,9 @@ impl Metadata for Album { Album { id: SpotifyId::from_raw(msg.get_gid()).unwrap(), name: msg.get_name().to_owned(), - artists: artists, - tracks: tracks, - covers: covers, + artists, + tracks, + covers, } } } @@ -309,7 +308,7 @@ impl Metadata for Playlist { Playlist { revision: msg.get_revision().to_vec(), name: msg.get_attributes().get_name().to_owned(), - tracks: tracks, + tracks, user: msg.get_owner_username().to_string(), } } @@ -342,7 +341,7 @@ impl Metadata for Artist { Artist { id: SpotifyId::from_raw(msg.get_gid()).unwrap(), name: msg.get_name().to_owned(), - top_tracks: top_tracks, + top_tracks, } } } @@ -388,8 +387,8 @@ impl Metadata for Episode { duration: msg.get_duration().to_owned(), language: msg.get_language().to_owned(), show: SpotifyId::from_raw(msg.get_show().get_gid()).unwrap(), - covers: covers, - files: files, + covers, + files, available: parse_restrictions(msg.get_restriction(), &country, "premium"), explicit: msg.get_explicit().to_owned(), } @@ -427,8 +426,8 @@ impl Metadata for Show { id: SpotifyId::from_raw(msg.get_gid()).unwrap(), name: msg.get_name().to_owned(), publisher: msg.get_publisher().to_owned(), - episodes: episodes, - covers: covers, + episodes, + covers, } } } diff --git a/playback/src/player.rs b/playback/src/player.rs index 6c9e516d1..0d2380e73 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -204,10 +204,10 @@ impl NormalisationData { let album_peak = file.read_f32::()?; let r = NormalisationData { - track_gain_db: track_gain_db, - track_peak: track_peak, - album_gain_db: album_gain_db, - album_peak: album_peak, + track_gain_db, + track_peak, + album_gain_db, + album_peak, }; Ok(r) @@ -1164,8 +1164,8 @@ impl PlayerInternal { }); self.state = PlayerState::Playing { - track_id: track_id, - play_request_id: play_request_id, + track_id, + play_request_id, decoder: loaded_track.decoder, normalisation_factor: loaded_track.normalisation_factor, stream_loader_controller: loaded_track.stream_loader_controller, @@ -1181,8 +1181,8 @@ impl PlayerInternal { self.ensure_sink_stopped(false); self.state = PlayerState::Paused { - track_id: track_id, - play_request_id: play_request_id, + track_id, + play_request_id, decoder: loaded_track.decoder, normalisation_factor: loaded_track.normalisation_factor, stream_loader_controller: loaded_track.stream_loader_controller, @@ -1229,7 +1229,7 @@ impl PlayerInternal { track_id: old_track_id, .. } => self.send_event(PlayerEvent::Changed { - old_track_id: old_track_id, + old_track_id, new_track_id: track_id, }), PlayerState::Stopped => self.send_event(PlayerEvent::Started { @@ -1726,10 +1726,7 @@ struct Subfile { impl Subfile { pub fn new(mut stream: T, offset: u64) -> Subfile { stream.seek(SeekFrom::Start(offset)).unwrap(); - Subfile { - stream: stream, - offset: offset, - } + Subfile { stream, offset } } } diff --git a/src/main.rs b/src/main.rs index ff9e564c4..5b445b2cb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -353,7 +353,7 @@ fn setup(args: &[String]) -> Setup { SessionConfig { user_agent: version::version_string(), - device_id: device_id, + device_id, proxy: matches.opt_str("proxy").or_else(|| std::env::var("http_proxy").ok()).map( |s| { match Url::parse(&s) { @@ -393,7 +393,7 @@ fn setup(args: &[String]) -> Setup { }) .unwrap_or_default(); PlayerConfig { - bitrate: bitrate, + bitrate, gapless: !matches.opt_present("disable-gapless"), normalisation: matches.opt_present("enable-volume-normalisation"), normalisation_type: gain_type, @@ -419,10 +419,10 @@ fn setup(args: &[String]) -> Setup { .unwrap_or_default(); ConnectConfig { - name: name, - device_type: device_type, + name, + device_type, volume: initial_volume, - volume_ctrl: volume_ctrl, + volume_ctrl, autoplay: matches.opt_present("autoplay"), } }; @@ -430,17 +430,17 @@ fn setup(args: &[String]) -> Setup { let enable_discovery = !matches.opt_present("disable-discovery"); Setup { - backend: backend, - cache: cache, - session_config: session_config, - player_config: player_config, - connect_config: connect_config, - credentials: credentials, - device: device, - enable_discovery: enable_discovery, - zeroconf_port: zeroconf_port, - mixer: mixer, - mixer_config: mixer_config, + backend, + cache, + session_config, + player_config, + connect_config, + credentials, + device, + enable_discovery, + zeroconf_port, + mixer, + mixer_config, player_event_program: matches.opt_str("onevent"), emit_sink_events: matches.opt_present("emit-sink-events"), } From e71a004e93d9376bb30834416cdd9248ad521246 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Sun, 28 Feb 2021 11:36:14 +0100 Subject: [PATCH 57/75] Refactor AudioFileFetch using async/await Previously, polling `AudioFileFetch` consisted of three parts: Handling stream loader commands, handling received data, and triggering preloading in stream mode when the number of open requests is sufficiently small. The first steps use channels which are polled, and if something's available, it's handled. The third step is executed on every call of `poll`. The first two could easily be refactored using a `tokio::select!`-loop. Therefore, counting the number of open requests was also refactored to fit into this scheme. They were previously counted using a shared `AtomicUsize`. Now, the number of open requests is stored exclusively in `AudioFileFetch`, increased on starting a request, and decreased by an oneshot channel that is fired when a request is finished. This allows us to `select` that channel in the loop too, and since loading ahead makes only sense if the number of open requests decreases, the third step is only executed in this case. `AudioFileFetch` does not implement `Future` anymore, but is rather used as helper struct in an async fn `audio_file_fetch`. --- audio/src/fetch.rs | 521 +++++++++++++++------------------------------ 1 file changed, 175 insertions(+), 346 deletions(-) diff --git a/audio/src/fetch.rs b/audio/src/fetch.rs index 5fdf9e74f..da3430962 100644 --- a/audio/src/fetch.rs +++ b/audio/src/fetch.rs @@ -1,11 +1,8 @@ use std::cmp::{max, min}; use std::fs; -use std::future::Future; use std::io::{self, Read, Seek, SeekFrom, Write}; -use std::pin::Pin; use std::sync::atomic::{self, AtomicUsize}; use std::sync::{Arc, Condvar, Mutex}; -use std::task::{Context, Poll}; use std::time::{Duration, Instant}; use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; @@ -236,7 +233,7 @@ struct AudioFileDownloadStatus { downloaded: RangeSet, } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, PartialEq, Eq)] enum DownloadStrategy { RandomAccess(), Streaming(), @@ -249,7 +246,6 @@ struct AudioFileShared { cond: Condvar, download_status: Mutex, download_strategy: Mutex, - number_of_open_requests: AtomicUsize, ping_time_ms: AtomicUsize, read_position: AtomicUsize, } @@ -358,7 +354,6 @@ impl AudioFileStreaming { downloaded: RangeSet::new(), }), download_strategy: Mutex::new(DownloadStrategy::RandomAccess()), // start with random access mode until someone tells us otherwise - number_of_open_requests: AtomicUsize::new(0), ping_time_ms: AtomicUsize::new(0), read_position: AtomicUsize::new(0), }); @@ -373,7 +368,7 @@ impl AudioFileStreaming { let (stream_loader_command_tx, stream_loader_command_rx) = mpsc::unbounded_channel::(); - let fetcher = AudioFileFetch::new( + session.spawn(audio_file_fetch( session.clone(), shared.clone(), initial_data_rx, @@ -382,9 +377,8 @@ impl AudioFileStreaming { write_file, stream_loader_command_rx, complete_tx, - ); + )); - session.spawn(fetcher); Ok(AudioFileStreaming { read_file, position: 0, @@ -442,17 +436,11 @@ async fn audio_file_fetch_receive_data( initial_data_offset: usize, initial_request_length: usize, request_sent_time: Instant, + mut measure_ping_time: bool, + finish_tx: mpsc::UnboundedSender<()>, ) { let mut data_offset = initial_data_offset; let mut request_length = initial_request_length; - let mut measure_ping_time = shared - .number_of_open_requests - .load(atomic::Ordering::SeqCst) - == 0; - - shared - .number_of_open_requests - .fetch_add(1, atomic::Ordering::SeqCst); let result = loop { let data = match data_rx.next().await { @@ -501,9 +489,7 @@ async fn audio_file_fetch_receive_data( shared.cond.notify_all(); } - shared - .number_of_open_requests - .fetch_sub(1, atomic::Ordering::SeqCst); + let _ = finish_tx.send(()); if result.is_err() { warn!( @@ -517,162 +503,6 @@ async fn audio_file_fetch_receive_data( ); } } -/* -async fn audio_file_fetch( - session: Session, - shared: Arc, - initial_data_rx: ChannelData, - initial_request_sent_time: Instant, - initial_data_length: usize, - - output: NamedTempFile, - stream_loader_command_rx: mpsc::UnboundedReceiver, - complete_tx: oneshot::Sender, -) { - let (file_data_tx, file_data_rx) = unbounded::(); - - let requested_range = Range::new(0, initial_data_length); - let mut download_status = shared.download_status.lock().unwrap(); - download_status.requested.add_range(&requested_range); - - session.spawn(audio_file_fetch_receive_data( - shared.clone(), - file_data_tx.clone(), - initial_data_rx, - 0, - initial_data_length, - initial_request_sent_time, - )); - - let mut network_response_times_ms: Vec::new(); - - let f1 = file_data_rx.map(|x| Ok::<_, ()>(x)).try_for_each(|x| { - match x { - ReceivedData::ResponseTimeMs(response_time_ms) => { - trace!("Ping time estimated as: {} ms.", response_time_ms); - - // record the response time - network_response_times_ms.push(response_time_ms); - - // prune old response times. Keep at most three. - while network_response_times_ms.len() > 3 { - network_response_times_ms.remove(0); - } - - // stats::median is experimental. So we calculate the median of up to three ourselves. - let ping_time_ms: usize = match network_response_times_ms.len() { - 1 => network_response_times_ms[0] as usize, - 2 => { - ((network_response_times_ms[0] + network_response_times_ms[1]) / 2) as usize - } - 3 => { - let mut times = network_response_times_ms.clone(); - times.sort(); - times[1] - } - _ => unreachable!(), - }; - - // store our new estimate for everyone to see - shared - .ping_time_ms - .store(ping_time_ms, atomic::Ordering::Relaxed); - } - ReceivedData::Data(data) => { - output - .as_mut() - .unwrap() - .seek(SeekFrom::Start(data.offset as u64)) - .unwrap(); - output - .as_mut() - .unwrap() - .write_all(data.data.as_ref()) - .unwrap(); - - let mut full = false; - - { - let mut download_status = shared.download_status.lock().unwrap(); - - let received_range = Range::new(data.offset, data.data.len()); - download_status.downloaded.add_range(&received_range); - shared.cond.notify_all(); - - if download_status.downloaded.contained_length_from_value(0) - >= shared.file_size - { - full = true; - } - - drop(download_status); - } - - if full { - self.finish(); - return future::ready(Err(())); - } - } - } - future::ready(Ok(())) - }); - - let f2 = stream_loader_command_rx.map(Ok::<_, ()>).try_for_each(|x| { - match cmd { - StreamLoaderCommand::Fetch(request) => { - self.download_range(request.start, request.length); - } - StreamLoaderCommand::RandomAccessMode() => { - *(shared.download_strategy.lock().unwrap()) = DownloadStrategy::RandomAccess(); - } - StreamLoaderCommand::StreamMode() => { - *(shared.download_strategy.lock().unwrap()) = DownloadStrategy::Streaming(); - } - StreamLoaderCommand::Close() => return future::ready(Err(())), - } - Ok(()) - }); - - let f3 = future::poll_fn(|_| { - if let DownloadStrategy::Streaming() = self.get_download_strategy() { - let number_of_open_requests = shared - .number_of_open_requests - .load(atomic::Ordering::SeqCst); - let max_requests_to_send = - MAX_PREFETCH_REQUESTS - min(MAX_PREFETCH_REQUESTS, number_of_open_requests); - - if max_requests_to_send > 0 { - let bytes_pending: usize = { - let download_status = shared.download_status.lock().unwrap(); - download_status - .requested - .minus(&download_status.downloaded) - .len() - }; - - let ping_time_seconds = - 0.001 * shared.ping_time_ms.load(atomic::Ordering::Relaxed) as f64; - let download_rate = session.channel().get_download_rate_estimate(); - - let desired_pending_bytes = max( - (PREFETCH_THRESHOLD_FACTOR * ping_time_seconds * shared.stream_data_rate as f64) - as usize, - (FAST_PREFETCH_THRESHOLD_FACTOR * ping_time_seconds * download_rate as f64) - as usize, - ); - - if bytes_pending < desired_pending_bytes { - self.pre_fetch_more_data( - desired_pending_bytes - bytes_pending, - max_requests_to_send, - ); - } - } - } - Poll::Pending - }); - future::select_all(vec![f1, f2, f3]).await -}*/ struct AudioFileFetch { session: Session, @@ -680,54 +510,21 @@ struct AudioFileFetch { output: Option, file_data_tx: mpsc::UnboundedSender, - file_data_rx: mpsc::UnboundedReceiver, - - stream_loader_command_rx: mpsc::UnboundedReceiver, complete_tx: Option>, network_response_times_ms: Vec, -} + number_of_open_requests: usize, -impl AudioFileFetch { - fn new( - session: Session, - shared: Arc, - initial_data_rx: ChannelData, - initial_request_sent_time: Instant, - initial_data_length: usize, - - output: NamedTempFile, - stream_loader_command_rx: mpsc::UnboundedReceiver, - complete_tx: oneshot::Sender, - ) -> AudioFileFetch { - let (file_data_tx, file_data_rx) = mpsc::unbounded_channel::(); - - { - let requested_range = Range::new(0, initial_data_length); - let mut download_status = shared.download_status.lock().unwrap(); - download_status.requested.add_range(&requested_range); - } - - session.spawn(audio_file_fetch_receive_data( - shared.clone(), - file_data_tx.clone(), - initial_data_rx, - 0, - initial_data_length, - initial_request_sent_time, - )); + download_finish_tx: mpsc::UnboundedSender<()>, +} - AudioFileFetch { - session, - shared, - output: Some(output), - file_data_tx, - file_data_rx, - stream_loader_command_rx, - complete_tx: Some(complete_tx), - network_response_times_ms: Vec::new(), - } - } +// Might be replaced by enum from std once stable +#[derive(PartialEq, Eq)] +enum ControlFlow { + Break, + Continue, +} +impl AudioFileFetch { fn get_download_strategy(&mut self) -> DownloadStrategy { *(self.shared.download_strategy.lock().unwrap()) } @@ -785,7 +582,11 @@ impl AudioFileFetch { range.start, range.length, Instant::now(), + self.number_of_open_requests == 0, + self.download_finish_tx.clone(), )); + + self.number_of_open_requests += 1; } } @@ -833,103 +634,86 @@ impl AudioFileFetch { } } - fn poll_file_data_rx(&mut self, cx: &mut Context<'_>) -> Poll<()> { - loop { - match self.file_data_rx.poll_recv(cx) { - Poll::Ready(None) => return Poll::Ready(()), - Poll::Ready(Some(ReceivedData::ResponseTimeMs(response_time_ms))) => { - trace!("Ping time estimated as: {} ms.", response_time_ms); - - // record the response time - self.network_response_times_ms.push(response_time_ms); + fn handle_file_data(&mut self, data: ReceivedData) -> ControlFlow { + match data { + ReceivedData::ResponseTimeMs(response_time_ms) => { + trace!("Ping time estimated as: {} ms.", response_time_ms); - // prune old response times. Keep at most three. - while self.network_response_times_ms.len() > 3 { - self.network_response_times_ms.remove(0); - } + // record the response time + self.network_response_times_ms.push(response_time_ms); - // stats::median is experimental. So we calculate the median of up to three ourselves. - let ping_time_ms: usize = match self.network_response_times_ms.len() { - 1 => self.network_response_times_ms[0] as usize, - 2 => { - ((self.network_response_times_ms[0] - + self.network_response_times_ms[1]) - / 2) as usize - } - 3 => { - let mut times = self.network_response_times_ms.clone(); - times.sort_unstable(); - times[1] - } - _ => unreachable!(), - }; - - // store our new estimate for everyone to see - self.shared - .ping_time_ms - .store(ping_time_ms, atomic::Ordering::Relaxed); + // prune old response times. Keep at most three. + while self.network_response_times_ms.len() > 3 { + self.network_response_times_ms.remove(0); } - Poll::Ready(Some(ReceivedData::Data(data))) => { - self.output - .as_mut() - .unwrap() - .seek(SeekFrom::Start(data.offset as u64)) - .unwrap(); - self.output - .as_mut() - .unwrap() - .write_all(data.data.as_ref()) - .unwrap(); - - let mut full = false; - - { - let mut download_status = self.shared.download_status.lock().unwrap(); - - let received_range = Range::new(data.offset, data.data.len()); - download_status.downloaded.add_range(&received_range); - self.shared.cond.notify_all(); - - if download_status.downloaded.contained_length_from_value(0) - >= self.shared.file_size - { - full = true; - } - - drop(download_status); - } - if full { - self.finish(); - return Poll::Ready(()); + // stats::median is experimental. So we calculate the median of up to three ourselves. + let ping_time_ms: usize = match self.network_response_times_ms.len() { + 1 => self.network_response_times_ms[0] as usize, + 2 => { + ((self.network_response_times_ms[0] + self.network_response_times_ms[1]) + / 2) as usize } + 3 => { + let mut times = self.network_response_times_ms.clone(); + times.sort_unstable(); + times[1] + } + _ => unreachable!(), + }; + + // store our new estimate for everyone to see + self.shared + .ping_time_ms + .store(ping_time_ms, atomic::Ordering::Relaxed); + } + ReceivedData::Data(data) => { + self.output + .as_mut() + .unwrap() + .seek(SeekFrom::Start(data.offset as u64)) + .unwrap(); + self.output + .as_mut() + .unwrap() + .write_all(data.data.as_ref()) + .unwrap(); + + let mut download_status = self.shared.download_status.lock().unwrap(); + + let received_range = Range::new(data.offset, data.data.len()); + download_status.downloaded.add_range(&received_range); + self.shared.cond.notify_all(); + + let full = download_status.downloaded.contained_length_from_value(0) + >= self.shared.file_size; + + drop(download_status); + + if full { + self.finish(); + return ControlFlow::Break; } - Poll::Pending => return Poll::Pending, } } + ControlFlow::Continue } - fn poll_stream_loader_command_rx(&mut self, cx: &mut Context<'_>) -> Poll<()> { - loop { - match self.stream_loader_command_rx.poll_recv(cx) { - Poll::Ready(None) => return Poll::Ready(()), - Poll::Ready(Some(cmd)) => match cmd { - StreamLoaderCommand::Fetch(request) => { - self.download_range(request.start, request.length); - } - StreamLoaderCommand::RandomAccessMode() => { - *(self.shared.download_strategy.lock().unwrap()) = - DownloadStrategy::RandomAccess(); - } - StreamLoaderCommand::StreamMode() => { - *(self.shared.download_strategy.lock().unwrap()) = - DownloadStrategy::Streaming(); - } - StreamLoaderCommand::Close() => return Poll::Ready(()), - }, - Poll::Pending => return Poll::Pending, + fn handle_stream_loader_command(&mut self, cmd: StreamLoaderCommand) -> ControlFlow { + match cmd { + StreamLoaderCommand::Fetch(request) => { + self.download_range(request.start, request.length); + } + StreamLoaderCommand::RandomAccessMode() => { + *(self.shared.download_strategy.lock().unwrap()) = DownloadStrategy::RandomAccess(); } + StreamLoaderCommand::StreamMode() => { + *(self.shared.download_strategy.lock().unwrap()) = DownloadStrategy::Streaming(); + self.trigger_preload(); + } + StreamLoaderCommand::Close() => return ControlFlow::Break, } + ControlFlow::Continue } fn finish(&mut self) { @@ -939,57 +723,102 @@ impl AudioFileFetch { output.seek(SeekFrom::Start(0)).unwrap(); let _ = complete_tx.send(output); } -} -impl Future for AudioFileFetch { - type Output = (); - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { - if let Poll::Ready(()) = self.poll_stream_loader_command_rx(cx) { - return Poll::Ready(()); + fn trigger_preload(&mut self) { + if self.number_of_open_requests >= MAX_PREFETCH_REQUESTS { + return; } - if let Poll::Ready(()) = self.poll_file_data_rx(cx) { - return Poll::Ready(()); + let max_requests_to_send = MAX_PREFETCH_REQUESTS - self.number_of_open_requests; + + let bytes_pending: usize = { + let download_status = self.shared.download_status.lock().unwrap(); + download_status + .requested + .minus(&download_status.downloaded) + .len() + }; + + let ping_time_seconds = + 0.001 * self.shared.ping_time_ms.load(atomic::Ordering::Relaxed) as f64; + let download_rate = self.session.channel().get_download_rate_estimate(); + + let desired_pending_bytes = max( + (PREFETCH_THRESHOLD_FACTOR * ping_time_seconds * self.shared.stream_data_rate as f64) + as usize, + (FAST_PREFETCH_THRESHOLD_FACTOR * ping_time_seconds * download_rate as f64) as usize, + ); + + if bytes_pending < desired_pending_bytes { + self.pre_fetch_more_data(desired_pending_bytes - bytes_pending, max_requests_to_send); } + } +} - if let DownloadStrategy::Streaming() = self.get_download_strategy() { - let number_of_open_requests = self - .shared - .number_of_open_requests - .load(atomic::Ordering::SeqCst); - let max_requests_to_send = - MAX_PREFETCH_REQUESTS - min(MAX_PREFETCH_REQUESTS, number_of_open_requests); - - if max_requests_to_send > 0 { - let bytes_pending: usize = { - let download_status = self.shared.download_status.lock().unwrap(); - download_status - .requested - .minus(&download_status.downloaded) - .len() - }; +async fn audio_file_fetch( + session: Session, + shared: Arc, + initial_data_rx: ChannelData, + initial_request_sent_time: Instant, + initial_data_length: usize, - let ping_time_seconds = - 0.001 * self.shared.ping_time_ms.load(atomic::Ordering::Relaxed) as f64; - let download_rate = self.session.channel().get_download_rate_estimate(); - - let desired_pending_bytes = max( - (PREFETCH_THRESHOLD_FACTOR - * ping_time_seconds - * self.shared.stream_data_rate as f64) as usize, - (FAST_PREFETCH_THRESHOLD_FACTOR * ping_time_seconds * download_rate as f64) - as usize, - ); - - if bytes_pending < desired_pending_bytes { - self.pre_fetch_more_data( - desired_pending_bytes - bytes_pending, - max_requests_to_send, - ); + output: NamedTempFile, + mut stream_loader_command_rx: mpsc::UnboundedReceiver, + complete_tx: oneshot::Sender, +) { + let (file_data_tx, mut file_data_rx) = mpsc::unbounded_channel(); + let (download_finish_tx, mut download_finish_rx) = mpsc::unbounded_channel(); + + { + let requested_range = Range::new(0, initial_data_length); + let mut download_status = shared.download_status.lock().unwrap(); + download_status.requested.add_range(&requested_range); + } + + session.spawn(audio_file_fetch_receive_data( + shared.clone(), + file_data_tx.clone(), + initial_data_rx, + 0, + initial_data_length, + initial_request_sent_time, + true, + download_finish_tx.clone(), + )); + + let mut fetch = AudioFileFetch { + session, + shared, + output: Some(output), + + file_data_tx, + complete_tx: Some(complete_tx), + network_response_times_ms: Vec::new(), + number_of_open_requests: 1, + + download_finish_tx, + }; + + loop { + tokio::select! { + cmd = stream_loader_command_rx.recv() => { + if cmd.map_or(true, |cmd| fetch.handle_stream_loader_command(cmd) == ControlFlow::Break) { + break; + } + }, + data = file_data_rx.recv() => { + if data.map_or(true, |data| fetch.handle_file_data(data) == ControlFlow::Break) { + break; + } + }, + _ = download_finish_rx.recv() => { + fetch.number_of_open_requests -= 1; + + if fetch.get_download_strategy() == DownloadStrategy::Streaming() { + fetch.trigger_preload(); } } } - Poll::Pending } } From ca255c17f06801ad9b79259233bd7a6b952b3942 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Sun, 28 Feb 2021 11:36:15 +0100 Subject: [PATCH 58/75] Split file fetch.rs --- audio/src/{fetch.rs => fetch/mod.rs} | 444 +------------------------- audio/src/fetch/receive.rs | 455 +++++++++++++++++++++++++++ 2 files changed, 461 insertions(+), 438 deletions(-) rename audio/src/{fetch.rs => fetch/mod.rs} (55%) create mode 100644 audio/src/fetch/receive.rs diff --git a/audio/src/fetch.rs b/audio/src/fetch/mod.rs similarity index 55% rename from audio/src/fetch.rs rename to audio/src/fetch/mod.rs index da3430962..c19fac2ec 100644 --- a/audio/src/fetch.rs +++ b/audio/src/fetch/mod.rs @@ -1,19 +1,21 @@ +mod receive; + use std::cmp::{max, min}; use std::fs; -use std::io::{self, Read, Seek, SeekFrom, Write}; +use std::io::{self, Read, Seek, SeekFrom}; use std::sync::atomic::{self, AtomicUsize}; use std::sync::{Arc, Condvar, Mutex}; use std::time::{Duration, Instant}; -use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; -use bytes::Bytes; +use byteorder::{BigEndian, ByteOrder}; use futures_util::{future, StreamExt, TryFutureExt, TryStreamExt}; -use librespot_core::channel::{Channel, ChannelData, ChannelError, ChannelHeaders}; +use librespot_core::channel::{ChannelData, ChannelError, ChannelHeaders}; use librespot_core::session::Session; use librespot_core::spotify_id::FileId; use tempfile::NamedTempFile; use tokio::sync::{mpsc, oneshot}; +use self::receive::{audio_file_fetch, request_range}; use crate::range_set::{Range, RangeSet}; const MINIMUM_DOWNLOAD_SIZE: usize = 1024 * 16; @@ -388,440 +390,6 @@ impl AudioFileStreaming { } } -fn request_range(session: &Session, file: FileId, offset: usize, length: usize) -> Channel { - assert!( - offset % 4 == 0, - "Range request start positions must be aligned by 4 bytes." - ); - assert!( - length % 4 == 0, - "Range request range lengths must be aligned by 4 bytes." - ); - let start = offset / 4; - let end = (offset + length) / 4; - - let (id, channel) = session.channel().allocate(); - - let mut data: Vec = Vec::new(); - data.write_u16::(id).unwrap(); - data.write_u8(0).unwrap(); - data.write_u8(1).unwrap(); - data.write_u16::(0x0000).unwrap(); - data.write_u32::(0x00000000).unwrap(); - data.write_u32::(0x00009C40).unwrap(); - data.write_u32::(0x00020000).unwrap(); - data.write(&file.0).unwrap(); - data.write_u32::(start as u32).unwrap(); - data.write_u32::(end as u32).unwrap(); - - session.send_packet(0x8, data); - - channel -} - -struct PartialFileData { - offset: usize, - data: Bytes, -} - -enum ReceivedData { - ResponseTimeMs(usize), - Data(PartialFileData), -} - -async fn audio_file_fetch_receive_data( - shared: Arc, - file_data_tx: mpsc::UnboundedSender, - mut data_rx: ChannelData, - initial_data_offset: usize, - initial_request_length: usize, - request_sent_time: Instant, - mut measure_ping_time: bool, - finish_tx: mpsc::UnboundedSender<()>, -) { - let mut data_offset = initial_data_offset; - let mut request_length = initial_request_length; - - let result = loop { - let data = match data_rx.next().await { - Some(Ok(data)) => data, - Some(Err(e)) => break Err(e), - None => break Ok(()), - }; - - if measure_ping_time { - let duration = Instant::now() - request_sent_time; - let duration_ms: u64; - if 0.001 * (duration.as_millis() as f64) > MAXIMUM_ASSUMED_PING_TIME_SECONDS { - duration_ms = (MAXIMUM_ASSUMED_PING_TIME_SECONDS * 1000.0) as u64; - } else { - duration_ms = duration.as_millis() as u64; - } - let _ = file_data_tx.send(ReceivedData::ResponseTimeMs(duration_ms as usize)); - measure_ping_time = false; - } - let data_size = data.len(); - let _ = file_data_tx.send(ReceivedData::Data(PartialFileData { - offset: data_offset, - data, - })); - data_offset += data_size; - if request_length < data_size { - warn!( - "Data receiver for range {} (+{}) received more data from server than requested.", - initial_data_offset, initial_request_length - ); - request_length = 0; - } else { - request_length -= data_size; - } - - if request_length == 0 { - break Ok(()); - } - }; - - if request_length > 0 { - let missing_range = Range::new(data_offset, request_length); - - let mut download_status = shared.download_status.lock().unwrap(); - download_status.requested.subtract_range(&missing_range); - shared.cond.notify_all(); - } - - let _ = finish_tx.send(()); - - if result.is_err() { - warn!( - "Error from channel for data receiver for range {} (+{}).", - initial_data_offset, initial_request_length - ); - } else if request_length > 0 { - warn!( - "Data receiver for range {} (+{}) received less data from server than requested.", - initial_data_offset, initial_request_length - ); - } -} - -struct AudioFileFetch { - session: Session, - shared: Arc, - output: Option, - - file_data_tx: mpsc::UnboundedSender, - complete_tx: Option>, - network_response_times_ms: Vec, - number_of_open_requests: usize, - - download_finish_tx: mpsc::UnboundedSender<()>, -} - -// Might be replaced by enum from std once stable -#[derive(PartialEq, Eq)] -enum ControlFlow { - Break, - Continue, -} - -impl AudioFileFetch { - fn get_download_strategy(&mut self) -> DownloadStrategy { - *(self.shared.download_strategy.lock().unwrap()) - } - - fn download_range(&mut self, mut offset: usize, mut length: usize) { - if length < MINIMUM_DOWNLOAD_SIZE { - length = MINIMUM_DOWNLOAD_SIZE; - } - - // ensure the values are within the bounds and align them by 4 for the spotify protocol. - if offset >= self.shared.file_size { - return; - } - - if length == 0 { - return; - } - - if offset + length > self.shared.file_size { - length = self.shared.file_size - offset; - } - - if offset % 4 != 0 { - length += offset % 4; - offset -= offset % 4; - } - - if length % 4 != 0 { - length += 4 - (length % 4); - } - - let mut ranges_to_request = RangeSet::new(); - ranges_to_request.add_range(&Range::new(offset, length)); - - let mut download_status = self.shared.download_status.lock().unwrap(); - - ranges_to_request.subtract_range_set(&download_status.downloaded); - ranges_to_request.subtract_range_set(&download_status.requested); - - for range in ranges_to_request.iter() { - let (_headers, data) = request_range( - &self.session, - self.shared.file_id, - range.start, - range.length, - ) - .split(); - - download_status.requested.add_range(range); - - self.session.spawn(audio_file_fetch_receive_data( - self.shared.clone(), - self.file_data_tx.clone(), - data, - range.start, - range.length, - Instant::now(), - self.number_of_open_requests == 0, - self.download_finish_tx.clone(), - )); - - self.number_of_open_requests += 1; - } - } - - fn pre_fetch_more_data(&mut self, bytes: usize, max_requests_to_send: usize) { - let mut bytes_to_go = bytes; - let mut requests_to_go = max_requests_to_send; - - while bytes_to_go > 0 && requests_to_go > 0 { - // determine what is still missing - let mut missing_data = RangeSet::new(); - missing_data.add_range(&Range::new(0, self.shared.file_size)); - { - let download_status = self.shared.download_status.lock().unwrap(); - missing_data.subtract_range_set(&download_status.downloaded); - missing_data.subtract_range_set(&download_status.requested); - } - - // download data from after the current read position first - let mut tail_end = RangeSet::new(); - let read_position = self.shared.read_position.load(atomic::Ordering::Relaxed); - tail_end.add_range(&Range::new( - read_position, - self.shared.file_size - read_position, - )); - let tail_end = tail_end.intersection(&missing_data); - - if !tail_end.is_empty() { - let range = tail_end.get_range(0); - let offset = range.start; - let length = min(range.length, bytes_to_go); - self.download_range(offset, length); - requests_to_go -= 1; - bytes_to_go -= length; - } else if !missing_data.is_empty() { - // ok, the tail is downloaded, download something fom the beginning. - let range = missing_data.get_range(0); - let offset = range.start; - let length = min(range.length, bytes_to_go); - self.download_range(offset, length); - requests_to_go -= 1; - bytes_to_go -= length; - } else { - return; - } - } - } - - fn handle_file_data(&mut self, data: ReceivedData) -> ControlFlow { - match data { - ReceivedData::ResponseTimeMs(response_time_ms) => { - trace!("Ping time estimated as: {} ms.", response_time_ms); - - // record the response time - self.network_response_times_ms.push(response_time_ms); - - // prune old response times. Keep at most three. - while self.network_response_times_ms.len() > 3 { - self.network_response_times_ms.remove(0); - } - - // stats::median is experimental. So we calculate the median of up to three ourselves. - let ping_time_ms: usize = match self.network_response_times_ms.len() { - 1 => self.network_response_times_ms[0] as usize, - 2 => { - ((self.network_response_times_ms[0] + self.network_response_times_ms[1]) - / 2) as usize - } - 3 => { - let mut times = self.network_response_times_ms.clone(); - times.sort_unstable(); - times[1] - } - _ => unreachable!(), - }; - - // store our new estimate for everyone to see - self.shared - .ping_time_ms - .store(ping_time_ms, atomic::Ordering::Relaxed); - } - ReceivedData::Data(data) => { - self.output - .as_mut() - .unwrap() - .seek(SeekFrom::Start(data.offset as u64)) - .unwrap(); - self.output - .as_mut() - .unwrap() - .write_all(data.data.as_ref()) - .unwrap(); - - let mut download_status = self.shared.download_status.lock().unwrap(); - - let received_range = Range::new(data.offset, data.data.len()); - download_status.downloaded.add_range(&received_range); - self.shared.cond.notify_all(); - - let full = download_status.downloaded.contained_length_from_value(0) - >= self.shared.file_size; - - drop(download_status); - - if full { - self.finish(); - return ControlFlow::Break; - } - } - } - ControlFlow::Continue - } - - fn handle_stream_loader_command(&mut self, cmd: StreamLoaderCommand) -> ControlFlow { - match cmd { - StreamLoaderCommand::Fetch(request) => { - self.download_range(request.start, request.length); - } - StreamLoaderCommand::RandomAccessMode() => { - *(self.shared.download_strategy.lock().unwrap()) = DownloadStrategy::RandomAccess(); - } - StreamLoaderCommand::StreamMode() => { - *(self.shared.download_strategy.lock().unwrap()) = DownloadStrategy::Streaming(); - self.trigger_preload(); - } - StreamLoaderCommand::Close() => return ControlFlow::Break, - } - ControlFlow::Continue - } - - fn finish(&mut self) { - let mut output = self.output.take().unwrap(); - let complete_tx = self.complete_tx.take().unwrap(); - - output.seek(SeekFrom::Start(0)).unwrap(); - let _ = complete_tx.send(output); - } - - fn trigger_preload(&mut self) { - if self.number_of_open_requests >= MAX_PREFETCH_REQUESTS { - return; - } - - let max_requests_to_send = MAX_PREFETCH_REQUESTS - self.number_of_open_requests; - - let bytes_pending: usize = { - let download_status = self.shared.download_status.lock().unwrap(); - download_status - .requested - .minus(&download_status.downloaded) - .len() - }; - - let ping_time_seconds = - 0.001 * self.shared.ping_time_ms.load(atomic::Ordering::Relaxed) as f64; - let download_rate = self.session.channel().get_download_rate_estimate(); - - let desired_pending_bytes = max( - (PREFETCH_THRESHOLD_FACTOR * ping_time_seconds * self.shared.stream_data_rate as f64) - as usize, - (FAST_PREFETCH_THRESHOLD_FACTOR * ping_time_seconds * download_rate as f64) as usize, - ); - - if bytes_pending < desired_pending_bytes { - self.pre_fetch_more_data(desired_pending_bytes - bytes_pending, max_requests_to_send); - } - } -} - -async fn audio_file_fetch( - session: Session, - shared: Arc, - initial_data_rx: ChannelData, - initial_request_sent_time: Instant, - initial_data_length: usize, - - output: NamedTempFile, - mut stream_loader_command_rx: mpsc::UnboundedReceiver, - complete_tx: oneshot::Sender, -) { - let (file_data_tx, mut file_data_rx) = mpsc::unbounded_channel(); - let (download_finish_tx, mut download_finish_rx) = mpsc::unbounded_channel(); - - { - let requested_range = Range::new(0, initial_data_length); - let mut download_status = shared.download_status.lock().unwrap(); - download_status.requested.add_range(&requested_range); - } - - session.spawn(audio_file_fetch_receive_data( - shared.clone(), - file_data_tx.clone(), - initial_data_rx, - 0, - initial_data_length, - initial_request_sent_time, - true, - download_finish_tx.clone(), - )); - - let mut fetch = AudioFileFetch { - session, - shared, - output: Some(output), - - file_data_tx, - complete_tx: Some(complete_tx), - network_response_times_ms: Vec::new(), - number_of_open_requests: 1, - - download_finish_tx, - }; - - loop { - tokio::select! { - cmd = stream_loader_command_rx.recv() => { - if cmd.map_or(true, |cmd| fetch.handle_stream_loader_command(cmd) == ControlFlow::Break) { - break; - } - }, - data = file_data_rx.recv() => { - if data.map_or(true, |data| fetch.handle_file_data(data) == ControlFlow::Break) { - break; - } - }, - _ = download_finish_rx.recv() => { - fetch.number_of_open_requests -= 1; - - if fetch.get_download_strategy() == DownloadStrategy::Streaming() { - fetch.trigger_preload(); - } - } - } - } -} - impl Read for AudioFileStreaming { fn read(&mut self, output: &mut [u8]) -> io::Result { let offset = self.position as usize; diff --git a/audio/src/fetch/receive.rs b/audio/src/fetch/receive.rs new file mode 100644 index 000000000..17f884f5e --- /dev/null +++ b/audio/src/fetch/receive.rs @@ -0,0 +1,455 @@ +use std::cmp::{max, min}; +use std::io::{Seek, SeekFrom, Write}; +use std::sync::{atomic, Arc}; +use std::time::Instant; + +use byteorder::{BigEndian, WriteBytesExt}; +use bytes::Bytes; +use futures_util::StreamExt; +use librespot_core::channel::{Channel, ChannelData}; +use librespot_core::session::Session; +use librespot_core::spotify_id::FileId; +use tempfile::NamedTempFile; +use tokio::sync::{mpsc, oneshot}; + +use crate::range_set::{Range, RangeSet}; + +use super::{AudioFileShared, DownloadStrategy, StreamLoaderCommand}; +use super::{ + FAST_PREFETCH_THRESHOLD_FACTOR, MAXIMUM_ASSUMED_PING_TIME_SECONDS, MAX_PREFETCH_REQUESTS, + MINIMUM_DOWNLOAD_SIZE, PREFETCH_THRESHOLD_FACTOR, +}; + +pub fn request_range(session: &Session, file: FileId, offset: usize, length: usize) -> Channel { + assert!( + offset % 4 == 0, + "Range request start positions must be aligned by 4 bytes." + ); + assert!( + length % 4 == 0, + "Range request range lengths must be aligned by 4 bytes." + ); + let start = offset / 4; + let end = (offset + length) / 4; + + let (id, channel) = session.channel().allocate(); + + let mut data: Vec = Vec::new(); + data.write_u16::(id).unwrap(); + data.write_u8(0).unwrap(); + data.write_u8(1).unwrap(); + data.write_u16::(0x0000).unwrap(); + data.write_u32::(0x00000000).unwrap(); + data.write_u32::(0x00009C40).unwrap(); + data.write_u32::(0x00020000).unwrap(); + data.write(&file.0).unwrap(); + data.write_u32::(start as u32).unwrap(); + data.write_u32::(end as u32).unwrap(); + + session.send_packet(0x8, data); + + channel +} + +struct PartialFileData { + offset: usize, + data: Bytes, +} + +enum ReceivedData { + ResponseTimeMs(usize), + Data(PartialFileData), +} + +async fn receive_data( + shared: Arc, + file_data_tx: mpsc::UnboundedSender, + mut data_rx: ChannelData, + initial_data_offset: usize, + initial_request_length: usize, + request_sent_time: Instant, + mut measure_ping_time: bool, + finish_tx: mpsc::UnboundedSender<()>, +) { + let mut data_offset = initial_data_offset; + let mut request_length = initial_request_length; + + let result = loop { + let data = match data_rx.next().await { + Some(Ok(data)) => data, + Some(Err(e)) => break Err(e), + None => break Ok(()), + }; + + if measure_ping_time { + let duration = Instant::now() - request_sent_time; + let duration_ms: u64; + if 0.001 * (duration.as_millis() as f64) > MAXIMUM_ASSUMED_PING_TIME_SECONDS { + duration_ms = (MAXIMUM_ASSUMED_PING_TIME_SECONDS * 1000.0) as u64; + } else { + duration_ms = duration.as_millis() as u64; + } + let _ = file_data_tx.send(ReceivedData::ResponseTimeMs(duration_ms as usize)); + measure_ping_time = false; + } + let data_size = data.len(); + let _ = file_data_tx.send(ReceivedData::Data(PartialFileData { + offset: data_offset, + data, + })); + data_offset += data_size; + if request_length < data_size { + warn!( + "Data receiver for range {} (+{}) received more data from server than requested.", + initial_data_offset, initial_request_length + ); + request_length = 0; + } else { + request_length -= data_size; + } + + if request_length == 0 { + break Ok(()); + } + }; + + if request_length > 0 { + let missing_range = Range::new(data_offset, request_length); + + let mut download_status = shared.download_status.lock().unwrap(); + download_status.requested.subtract_range(&missing_range); + shared.cond.notify_all(); + } + + let _ = finish_tx.send(()); + + if result.is_err() { + warn!( + "Error from channel for data receiver for range {} (+{}).", + initial_data_offset, initial_request_length + ); + } else if request_length > 0 { + warn!( + "Data receiver for range {} (+{}) received less data from server than requested.", + initial_data_offset, initial_request_length + ); + } +} + +struct AudioFileFetch { + session: Session, + shared: Arc, + output: Option, + + file_data_tx: mpsc::UnboundedSender, + complete_tx: Option>, + network_response_times_ms: Vec, + number_of_open_requests: usize, + + download_finish_tx: mpsc::UnboundedSender<()>, +} + +// Might be replaced by enum from std once stable +#[derive(PartialEq, Eq)] +enum ControlFlow { + Break, + Continue, +} + +impl AudioFileFetch { + fn get_download_strategy(&mut self) -> DownloadStrategy { + *(self.shared.download_strategy.lock().unwrap()) + } + + fn download_range(&mut self, mut offset: usize, mut length: usize) { + if length < MINIMUM_DOWNLOAD_SIZE { + length = MINIMUM_DOWNLOAD_SIZE; + } + + // ensure the values are within the bounds and align them by 4 for the spotify protocol. + if offset >= self.shared.file_size { + return; + } + + if length == 0 { + return; + } + + if offset + length > self.shared.file_size { + length = self.shared.file_size - offset; + } + + if offset % 4 != 0 { + length += offset % 4; + offset -= offset % 4; + } + + if length % 4 != 0 { + length += 4 - (length % 4); + } + + let mut ranges_to_request = RangeSet::new(); + ranges_to_request.add_range(&Range::new(offset, length)); + + let mut download_status = self.shared.download_status.lock().unwrap(); + + ranges_to_request.subtract_range_set(&download_status.downloaded); + ranges_to_request.subtract_range_set(&download_status.requested); + + for range in ranges_to_request.iter() { + let (_headers, data) = request_range( + &self.session, + self.shared.file_id, + range.start, + range.length, + ) + .split(); + + download_status.requested.add_range(range); + + self.session.spawn(receive_data( + self.shared.clone(), + self.file_data_tx.clone(), + data, + range.start, + range.length, + Instant::now(), + self.number_of_open_requests == 0, + self.download_finish_tx.clone(), + )); + + self.number_of_open_requests += 1; + } + } + + fn pre_fetch_more_data(&mut self, bytes: usize, max_requests_to_send: usize) { + let mut bytes_to_go = bytes; + let mut requests_to_go = max_requests_to_send; + + while bytes_to_go > 0 && requests_to_go > 0 { + // determine what is still missing + let mut missing_data = RangeSet::new(); + missing_data.add_range(&Range::new(0, self.shared.file_size)); + { + let download_status = self.shared.download_status.lock().unwrap(); + missing_data.subtract_range_set(&download_status.downloaded); + missing_data.subtract_range_set(&download_status.requested); + } + + // download data from after the current read position first + let mut tail_end = RangeSet::new(); + let read_position = self.shared.read_position.load(atomic::Ordering::Relaxed); + tail_end.add_range(&Range::new( + read_position, + self.shared.file_size - read_position, + )); + let tail_end = tail_end.intersection(&missing_data); + + if !tail_end.is_empty() { + let range = tail_end.get_range(0); + let offset = range.start; + let length = min(range.length, bytes_to_go); + self.download_range(offset, length); + requests_to_go -= 1; + bytes_to_go -= length; + } else if !missing_data.is_empty() { + // ok, the tail is downloaded, download something fom the beginning. + let range = missing_data.get_range(0); + let offset = range.start; + let length = min(range.length, bytes_to_go); + self.download_range(offset, length); + requests_to_go -= 1; + bytes_to_go -= length; + } else { + return; + } + } + } + + fn handle_file_data(&mut self, data: ReceivedData) -> ControlFlow { + match data { + ReceivedData::ResponseTimeMs(response_time_ms) => { + trace!("Ping time estimated as: {} ms.", response_time_ms); + + // record the response time + self.network_response_times_ms.push(response_time_ms); + + // prune old response times. Keep at most three. + while self.network_response_times_ms.len() > 3 { + self.network_response_times_ms.remove(0); + } + + // stats::median is experimental. So we calculate the median of up to three ourselves. + let ping_time_ms: usize = match self.network_response_times_ms.len() { + 1 => self.network_response_times_ms[0] as usize, + 2 => { + ((self.network_response_times_ms[0] + self.network_response_times_ms[1]) + / 2) as usize + } + 3 => { + let mut times = self.network_response_times_ms.clone(); + times.sort_unstable(); + times[1] + } + _ => unreachable!(), + }; + + // store our new estimate for everyone to see + self.shared + .ping_time_ms + .store(ping_time_ms, atomic::Ordering::Relaxed); + } + ReceivedData::Data(data) => { + self.output + .as_mut() + .unwrap() + .seek(SeekFrom::Start(data.offset as u64)) + .unwrap(); + self.output + .as_mut() + .unwrap() + .write_all(data.data.as_ref()) + .unwrap(); + + let mut download_status = self.shared.download_status.lock().unwrap(); + + let received_range = Range::new(data.offset, data.data.len()); + download_status.downloaded.add_range(&received_range); + self.shared.cond.notify_all(); + + let full = download_status.downloaded.contained_length_from_value(0) + >= self.shared.file_size; + + drop(download_status); + + if full { + self.finish(); + return ControlFlow::Break; + } + } + } + ControlFlow::Continue + } + + fn handle_stream_loader_command(&mut self, cmd: StreamLoaderCommand) -> ControlFlow { + match cmd { + StreamLoaderCommand::Fetch(request) => { + self.download_range(request.start, request.length); + } + StreamLoaderCommand::RandomAccessMode() => { + *(self.shared.download_strategy.lock().unwrap()) = DownloadStrategy::RandomAccess(); + } + StreamLoaderCommand::StreamMode() => { + *(self.shared.download_strategy.lock().unwrap()) = DownloadStrategy::Streaming(); + self.trigger_preload(); + } + StreamLoaderCommand::Close() => return ControlFlow::Break, + } + ControlFlow::Continue + } + + fn finish(&mut self) { + let mut output = self.output.take().unwrap(); + let complete_tx = self.complete_tx.take().unwrap(); + + output.seek(SeekFrom::Start(0)).unwrap(); + let _ = complete_tx.send(output); + } + + fn trigger_preload(&mut self) { + if self.number_of_open_requests >= MAX_PREFETCH_REQUESTS { + return; + } + + let max_requests_to_send = MAX_PREFETCH_REQUESTS - self.number_of_open_requests; + + let bytes_pending: usize = { + let download_status = self.shared.download_status.lock().unwrap(); + download_status + .requested + .minus(&download_status.downloaded) + .len() + }; + + let ping_time_seconds = + 0.001 * self.shared.ping_time_ms.load(atomic::Ordering::Relaxed) as f64; + let download_rate = self.session.channel().get_download_rate_estimate(); + + let desired_pending_bytes = max( + (PREFETCH_THRESHOLD_FACTOR * ping_time_seconds * self.shared.stream_data_rate as f64) + as usize, + (FAST_PREFETCH_THRESHOLD_FACTOR * ping_time_seconds * download_rate as f64) as usize, + ); + + if bytes_pending < desired_pending_bytes { + self.pre_fetch_more_data(desired_pending_bytes - bytes_pending, max_requests_to_send); + } + } +} + +pub(super) async fn audio_file_fetch( + session: Session, + shared: Arc, + initial_data_rx: ChannelData, + initial_request_sent_time: Instant, + initial_data_length: usize, + + output: NamedTempFile, + mut stream_loader_command_rx: mpsc::UnboundedReceiver, + complete_tx: oneshot::Sender, +) { + let (file_data_tx, mut file_data_rx) = mpsc::unbounded_channel(); + let (download_finish_tx, mut download_finish_rx) = mpsc::unbounded_channel(); + + { + let requested_range = Range::new(0, initial_data_length); + let mut download_status = shared.download_status.lock().unwrap(); + download_status.requested.add_range(&requested_range); + } + + session.spawn(receive_data( + shared.clone(), + file_data_tx.clone(), + initial_data_rx, + 0, + initial_data_length, + initial_request_sent_time, + true, + download_finish_tx.clone(), + )); + + let mut fetch = AudioFileFetch { + session, + shared, + output: Some(output), + + file_data_tx, + complete_tx: Some(complete_tx), + network_response_times_ms: Vec::new(), + number_of_open_requests: 1, + + download_finish_tx, + }; + + loop { + tokio::select! { + cmd = stream_loader_command_rx.recv() => { + if cmd.map_or(true, |cmd| fetch.handle_stream_loader_command(cmd) == ControlFlow::Break) { + break; + } + }, + data = file_data_rx.recv() => { + if data.map_or(true, |data| fetch.handle_file_data(data) == ControlFlow::Break) { + break; + } + }, + _ = download_finish_rx.recv() => { + fetch.number_of_open_requests -= 1; + + if fetch.get_download_strategy() == DownloadStrategy::Streaming() { + fetch.trigger_preload(); + } + } + } + } +} From ec1ec59b8a33d24d69018350da0851ef310e2732 Mon Sep 17 00:00:00 2001 From: ThouCheese Date: Sat, 6 Mar 2021 01:29:08 +0100 Subject: [PATCH 59/75] update examples Re-add default impl to SessionConfig and make Credentials::with_password generic over Into add docs for Credential reintroduce old Default impl for SessionConfig use the third argument for the track-to-play rather than a testing id --- Cargo.lock | 12 ++++++++++++ core/Cargo.toml | 1 + core/src/authentication.rs | 18 +++++++++++++++--- core/src/config.rs | 12 ++++++++++++ examples/get_token.rs | 22 ++++++++-------------- examples/play.rs | 26 ++++++++++---------------- examples/playlist_tracks.rs | 24 +++++++++--------------- 7 files changed, 67 insertions(+), 48 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 65493a277..461095f3f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "addr2line" version = "0.14.1" @@ -1358,6 +1360,7 @@ dependencies = [ "tokio-stream", "tokio-util", "url", + "uuid", "vergen", ] @@ -2801,6 +2804,15 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom", +] + [[package]] name = "vergen" version = "3.2.0" diff --git a/core/Cargo.toml b/core/Cargo.toml index 373e30885..9b2c6a524 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -40,6 +40,7 @@ tokio = { version = "1.0", features = ["io-util", "net", "rt", "sync"] } tokio-stream = "0.1" tokio-util = { version = "0.6", features = ["codec"] } url = "2.1" +uuid = { version = "0.8", default-features = false, features = ["v4"] } [build-dependencies] rand = "0.8" diff --git a/core/src/authentication.rs b/core/src/authentication.rs index 283935394..2992abcdf 100644 --- a/core/src/authentication.rs +++ b/core/src/authentication.rs @@ -10,6 +10,7 @@ use sha1::{Digest, Sha1}; use crate::protocol::authentication::AuthenticationType; +/// The credentials are used to log into the Spotify API. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Credentials { pub username: String, @@ -25,11 +26,22 @@ pub struct Credentials { } impl Credentials { - pub fn with_password(username: String, password: String) -> Credentials { + /// Intialize these credentials from a username and a password. + /// + /// ### Example + /// ```rust + /// use librespot_core::authentication::Credentials; + /// + /// let creds = Credentials::with_password("my account", "my password"); + /// ``` + pub fn with_password( + username: impl Into, + password: impl Into, + ) -> Credentials { Credentials { - username, + username: username.into(), auth_type: AuthenticationType::AUTHENTICATION_USER_PASS, - auth_data: password.into_bytes(), + auth_data: password.into().into_bytes(), } } diff --git a/core/src/config.rs b/core/src/config.rs index 469b935a2..269246406 100644 --- a/core/src/config.rs +++ b/core/src/config.rs @@ -10,6 +10,18 @@ pub struct SessionConfig { pub ap_port: Option, } +impl Default for SessionConfig { + fn default() -> SessionConfig { + let device_id = uuid::Uuid::new_v4().to_hyphenated().to_string(); + SessionConfig { + user_agent: crate::version::version_string(), + device_id, + proxy: None, + ap_port: None, + } + } +} + #[derive(Clone, Copy, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)] pub enum DeviceType { Unknown = 0, diff --git a/examples/get_token.rs b/examples/get_token.rs index d722e994a..15b97bcb9 100644 --- a/examples/get_token.rs +++ b/examples/get_token.rs @@ -1,5 +1,4 @@ use std::env; -use tokio_core::reactor::Core; use librespot::core::authentication::Credentials; use librespot::core::config::SessionConfig; @@ -9,29 +8,24 @@ use librespot::core::session::Session; const SCOPES: &str = "streaming,user-read-playback-state,user-modify-playback-state,user-read-currently-playing"; -fn main() { - let mut core = Core::new().unwrap(); - let handle = core.handle(); - +#[tokio::main] +async fn main() { let session_config = SessionConfig::default(); let args: Vec<_> = env::args().collect(); if args.len() != 4 { - println!("Usage: {} USERNAME PASSWORD CLIENT_ID", args[0]); + eprintln!("Usage: {} USERNAME PASSWORD CLIENT_ID", args[0]); + return; } - let username = args[1].to_owned(); - let password = args[2].to_owned(); - let client_id = &args[3]; println!("Connecting.."); - let credentials = Credentials::with_password(username, password); - let session = core - .run(Session::connect(session_config, credentials, None, handle)) - .unwrap(); + let credentials = Credentials::with_password(&args[1], &args[2]); + let session = Session::connect(session_config, credentials, None).await.unwrap(); println!( "Token: {:#?}", - core.run(keymaster::get_token(&session, &client_id, SCOPES)) + keymaster::get_token(&session, &args[3], SCOPES) + .await .unwrap() ); } diff --git a/examples/play.rs b/examples/play.rs index 4ba4c5b5a..9b1988a6a 100644 --- a/examples/play.rs +++ b/examples/play.rs @@ -1,47 +1,41 @@ use std::env; -use tokio_core::reactor::Core; use librespot::core::authentication::Credentials; use librespot::core::config::SessionConfig; use librespot::core::session::Session; use librespot::core::spotify_id::SpotifyId; use librespot::playback::config::PlayerConfig; - use librespot::playback::audio_backend; use librespot::playback::player::Player; -fn main() { - let mut core = Core::new().unwrap(); - let handle = core.handle(); - +#[tokio::main] +async fn main() { let session_config = SessionConfig::default(); let player_config = PlayerConfig::default(); let args: Vec<_> = env::args().collect(); if args.len() != 4 { - println!("Usage: {} USERNAME PASSWORD TRACK", args[0]); + eprintln!("Usage: {} USERNAME PASSWORD TRACK", args[0]); + return; } - let username = args[1].to_owned(); - let password = args[2].to_owned(); - let credentials = Credentials::with_password(username, password); + let credentials = Credentials::with_password(&args[1], &args[2]); let track = SpotifyId::from_base62(&args[3]).unwrap(); let backend = audio_backend::find(None).unwrap(); println!("Connecting .."); - let session = core - .run(Session::connect(session_config, credentials, None, handle)) - .unwrap(); + let session = Session::connect(session_config, credentials, None).await.unwrap(); - let (mut player, _) = Player::new(player_config, session.clone(), None, move || { - (backend)(None) + let (mut player, _) = Player::new(player_config, session, None, move || { + backend(None) }); player.load(track, true, 0); println!("Playing..."); - core.run(player.get_end_of_track_future()).unwrap(); + + player.await_end_of_track().await; println!("Done"); } diff --git a/examples/playlist_tracks.rs b/examples/playlist_tracks.rs index fc288d188..7bd95ae25 100644 --- a/examples/playlist_tracks.rs +++ b/examples/playlist_tracks.rs @@ -1,6 +1,5 @@ use env_logger; use std::env; -use tokio_core::reactor::Core; use librespot::core::authentication::Credentials; use librespot::core::config::SessionConfig; @@ -8,35 +7,30 @@ use librespot::core::session::Session; use librespot::core::spotify_id::SpotifyId; use librespot::metadata::{Metadata, Playlist, Track}; -fn main() { +#[tokio::main] +async fn main() { env_logger::init(); - let mut core = Core::new().unwrap(); - let handle = core.handle(); - let session_config = SessionConfig::default(); let args: Vec<_> = env::args().collect(); if args.len() != 4 { - println!("Usage: {} USERNAME PASSWORD PLAYLIST", args[0]); + eprintln!("Usage: {} USERNAME PASSWORD PLAYLIST", args[0]); + return; } - let username = args[1].to_owned(); - let password = args[2].to_owned(); - let credentials = Credentials::with_password(username, password); + let credentials = Credentials::with_password(&args[1], &args[2]); - let uri_split = args[3].split(":"); + let uri_split = args[3].split(':'); let uri_parts: Vec<&str> = uri_split.collect(); println!("{}, {}, {}", uri_parts[0], uri_parts[1], uri_parts[2]); let plist_uri = SpotifyId::from_base62(uri_parts[2]).unwrap(); - let session = core - .run(Session::connect(session_config, credentials, None, handle)) - .unwrap(); + let session = Session::connect(session_config, credentials, None).await.unwrap(); - let plist = core.run(Playlist::get(&session, plist_uri)).unwrap(); + let plist = Playlist::get(&session, plist_uri).await.unwrap(); println!("{:?}", plist); for track_id in plist.tracks { - let plist_track = core.run(Track::get(&session, track_id)).unwrap(); + let plist_track = Track::get(&session, track_id).await.unwrap(); println!("track: {} ", plist_track.name); } } From 95fedf53573c09683b49de4801bcbc46345ff9f4 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Wed, 17 Mar 2021 21:24:28 +0100 Subject: [PATCH 60/75] Add back hyper-proxy --- Cargo.lock | 101 ++++++++++++++++++++------------- Cargo.toml | 1 - core/Cargo.toml | 6 +- core/src/apresolve.rs | 111 ++++++++++++++++++------------------- core/src/connection/mod.rs | 53 ++++++++++-------- core/src/lib.rs | 15 ++++- core/src/proxytunnel.rs | 62 ++------------------- core/src/session.rs | 6 +- 8 files changed, 168 insertions(+), 187 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 65493a277..c654e7057 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -581,6 +581,21 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "futures" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f55667319111d593ba876406af7c409c0ebb44dc4be6132a783ccf163ea14c1" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.13" @@ -588,6 +603,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c2dd2df839b57db9ab69c2c9d8f3e8c81984781937fe2807dc6dcf3b2ad2939" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -607,6 +623,12 @@ dependencies = [ "futures-util", ] +[[package]] +name = "futures-io" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71c2c65c57704c32f5241c1223167c2c3294fd34ac020c807ddbe6db287ba59" + [[package]] name = "futures-macro" version = "0.3.13" @@ -637,10 +659,13 @@ version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1812c7ab8aedf8d6f2701a43e1243acdbcc2b36ab26e2ad421eb99ac963d96d1" dependencies = [ + "futures-channel", "futures-core", + "futures-io", "futures-macro", "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", "proc-macro-hack", @@ -851,30 +876,29 @@ dependencies = [ ] [[package]] -name = "h2" -version = "0.3.0" +name = "headers" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b67e66362108efccd8ac053abafc8b7a8d86a37e6e48fc4f6f7485eb5e9e6a5" +checksum = "f0b7591fb62902706ae8e7aaff416b1b0fa2c0fd0878b46dc13baa3712d8a855" dependencies = [ + "base64", + "bitflags", "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", + "headers-core", "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", - "tracing-futures", + "mime", + "sha-1", + "time 0.1.43", ] [[package]] -name = "hashbrown" -version = "0.9.1" +name = "headers-core" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" +checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +dependencies = [ + "http", +] [[package]] name = "heck" @@ -970,7 +994,6 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2", "http", "http-body", "httparse", @@ -984,6 +1007,21 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-proxy" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca815a891b24fdfb243fa3239c86154392b0953ee584aa1a2a1f66d20cbe75cc" +dependencies = [ + "bytes", + "futures", + "headers", + "http", + "hyper", + "tokio", + "tower-service", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -1022,16 +1060,6 @@ dependencies = [ "libc", ] -[[package]] -name = "indexmap" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b" -dependencies = [ - "autocfg", - "hashbrown", -] - [[package]] name = "instant" version = "0.1.9" @@ -1333,13 +1361,14 @@ dependencies = [ "base64", "byteorder", "bytes", - "cfg-if 1.0.0", "env_logger", "futures-core", "futures-util", "hmac", + "http", "httparse", "hyper", + "hyper-proxy", "librespot-protocol", "log", "num-bigint", @@ -1469,6 +1498,12 @@ version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + [[package]] name = "miniz_oxide" version = "0.4.3" @@ -2691,16 +2726,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project", - "tracing", -] - [[package]] name = "try-lock" version = "0.2.3" diff --git a/Cargo.toml b/Cargo.toml index 6b8cbee50..8f3e44c28 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,7 +59,6 @@ sha-1 = "0.9" [features] apresolve = ["librespot-core/apresolve"] -apresolve-http2 = ["librespot-core/apresolve-http2"] alsa-backend = ["librespot-playback/alsa-backend"] portaudio-backend = ["librespot-playback/portaudio-backend"] diff --git a/core/Cargo.toml b/core/Cargo.toml index 373e30885..ff4d2862c 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -17,12 +17,13 @@ aes = "0.6" base64 = "0.13" byteorder = "1.4" bytes = "1.0" -cfg-if = "1" futures-core = { version = "0.3", default-features = false } futures-util = { version = "0.3", default-features = false, features = ["alloc", "bilock", "unstable", "sink"] } hmac = "0.10" httparse = "1.3" +http = "0.2" hyper = { version = "0.14", optional = true, features = ["client", "tcp", "http1"] } +hyper-proxy = { version = "0.9.1", optional = true, default-features = false } log = "0.4" num-bigint = "0.3" num-integer = "0.1" @@ -50,5 +51,4 @@ env_logger = "*" tokio = {version = "1.0", features = ["macros"] } [features] -apresolve = ["hyper"] -apresolve-http2 = ["apresolve", "hyper/http2"] +apresolve = ["hyper", "hyper-proxy"] diff --git a/core/src/apresolve.rs b/core/src/apresolve.rs index 531a3e074..c954dab5b 100644 --- a/core/src/apresolve.rs +++ b/core/src/apresolve.rs @@ -1,73 +1,68 @@ -const AP_FALLBACK: &str = "ap.spotify.com:443"; +use std::error::Error; +use hyper::client::HttpConnector; +use hyper::{Body, Client, Method, Request, Uri}; +use hyper_proxy::{Intercept, Proxy, ProxyConnector}; +use serde::Deserialize; use url::Url; -cfg_if! { - if #[cfg(feature = "apresolve")] { - const APRESOLVE_ENDPOINT: &str = "http://apresolve.spotify.com:80"; +use super::AP_FALLBACK; - use std::error::Error; +const APRESOLVE_ENDPOINT: &str = "http://apresolve.spotify.com:80"; - use hyper::{Body, Client, Method, Request, Uri}; - use serde::{Serialize, Deserialize}; - - use crate::proxytunnel::ProxyTunnel; - - #[derive(Clone, Debug, Serialize, Deserialize)] - pub struct APResolveData { - ap_list: Vec, - } +#[derive(Clone, Debug, Deserialize)] +struct APResolveData { + ap_list: Vec, +} - async fn apresolve(proxy: &Option, ap_port: &Option) -> Result> { - let port = ap_port.unwrap_or(443); +async fn try_apresolve( + proxy: Option<&Url>, + ap_port: Option, +) -> Result> { + let port = ap_port.unwrap_or(443); - let req = Request::builder() - .method(Method::GET) - .uri( - APRESOLVE_ENDPOINT - .parse::() - .expect("invalid AP resolve URL"), - ) - .body(Body::empty())?; + let mut req = Request::new(Body::empty()); + *req.method_mut() = Method::GET; + // panic safety: APRESOLVE_ENDPOINT above is valid url. + *req.uri_mut() = APRESOLVE_ENDPOINT.parse().expect("invalid AP resolve URL"); - let response = if let Some(url) = proxy { - Client::builder() - .build(ProxyTunnel::new(&url.socket_addrs(|| None)?[..])?) - .request(req) - .await? - } else { - Client::new().request(req).await? - }; + let response = if let Some(url) = proxy { + // Panic safety: all URLs are valid URIs + let uri = url.to_string().parse().unwrap(); + let proxy = Proxy::new(Intercept::All, uri); + let connector = HttpConnector::new(); + let proxy_connector = ProxyConnector::from_proxy_unsecured(connector, proxy); + Client::builder() + .build(proxy_connector) + .request(req) + .await? + } else { + Client::new().request(req).await? + }; - let body = hyper::body::to_bytes(response.into_body()).await?; - let data: APResolveData = serde_json::from_slice(body.as_ref())?; + let body = hyper::body::to_bytes(response.into_body()).await?; + let data: APResolveData = serde_json::from_slice(body.as_ref())?; - let ap = if ap_port.is_some() || proxy.is_some() { - data.ap_list.into_iter().find_map(|ap| { - if ap.parse::().ok()?.port()? == port { - Some(ap) - } else { - None - } - }) + let ap = if ap_port.is_some() || proxy.is_some() { + data.ap_list.into_iter().find_map(|ap| { + if ap.parse::().ok()?.port()? == port { + Some(ap) } else { - data.ap_list.into_iter().next() + None } - .ok_or("empty AP List")?; - - Ok(ap) - } - - pub async fn apresolve_or_fallback(proxy: &Option, ap_port: &Option) -> String { - apresolve(proxy, ap_port).await.unwrap_or_else(|e| { - warn!("Failed to resolve Access Point: {}", e); - warn!("Using fallback \"{}\"", AP_FALLBACK); - AP_FALLBACK.into() - }) - } + }) } else { - pub async fn apresolve_or_fallback(_: &Option, _: &Option) -> String { - AP_FALLBACK.to_string() - } + data.ap_list.into_iter().next() } + .ok_or("empty AP List")?; + + Ok(ap) +} + +pub async fn apresolve(proxy: Option<&Url>, ap_port: Option) -> String { + try_apresolve(proxy, ap_port).await.unwrap_or_else(|e| { + warn!("Failed to resolve Access Point: {}", e); + warn!("Using fallback \"{}\"", AP_FALLBACK); + AP_FALLBACK.into() + }) } diff --git a/core/src/connection/mod.rs b/core/src/connection/mod.rs index b715d3578..ab353669c 100644 --- a/core/src/connection/mod.rs +++ b/core/src/connection/mod.rs @@ -58,25 +58,11 @@ impl From for AuthenticationError { } } -pub async fn connect(addr: String, proxy: &Option) -> io::Result { - let socket = if let Some(proxy) = proxy { - info!("Using proxy \"{}\"", proxy); +pub async fn connect(addr: String, proxy: Option<&Url>) -> io::Result { + let socket = if let Some(proxy_url) = proxy { + info!("Using proxy \"{}\"", proxy_url); - let mut split = addr.rsplit(':'); - - let port = split - .next() - .unwrap() // will never panic, split iterator contains at least one element - .parse() - .map_err(|e| { - io::Error::new(io::ErrorKind::InvalidInput, format!("Invalid port: {}", e)) - })?; - - let host = split - .next() - .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Missing port"))?; - - let socket_addr = proxy.socket_addrs(|| None).and_then(|addrs| { + let socket_addr = proxy_url.socket_addrs(|| None).and_then(|addrs| { addrs.into_iter().next().ok_or_else(|| { io::Error::new( io::ErrorKind::NotFound, @@ -86,13 +72,34 @@ pub async fn connect(addr: String, proxy: &Option) -> io::Result })?; let socket = TcpStream::connect(&socket_addr).await?; - proxytunnel::connect(socket, host, port).await? + let uri = addr.parse::().map_err(|_| { + io::Error::new( + io::ErrorKind::InvalidData, + "Can't parse access point address", + ) + })?; + let host = uri.host().ok_or_else(|| { + io::Error::new( + io::ErrorKind::InvalidInput, + "The access point address contains no hostname", + ) + })?; + let port = uri.port().ok_or_else(|| { + io::Error::new( + io::ErrorKind::InvalidInput, + "The access point address contains no port", + ) + })?; + + proxytunnel::proxy_connect(socket, host, port.as_str()).await? } else { - let socket_addr = addr.to_socket_addrs().and_then(|mut iter| { - iter.next().ok_or_else(|| { - io::Error::new(io::ErrorKind::NotFound, "Can't resolve server address") - }) + let socket_addr = addr.to_socket_addrs()?.next().ok_or_else(|| { + io::Error::new( + io::ErrorKind::NotFound, + "Can't resolve access point address", + ) })?; + TcpStream::connect(&socket_addr).await? }; diff --git a/core/src/lib.rs b/core/src/lib.rs index 4ebe85819..320967f70 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -2,15 +2,12 @@ #[macro_use] extern crate log; -#[macro_use] -extern crate cfg_if; use librespot_protocol as protocol; #[macro_use] mod component; -mod apresolve; pub mod audio_key; pub mod authentication; pub mod cache; @@ -25,3 +22,15 @@ pub mod session; pub mod spotify_id; pub mod util; pub mod version; + +const AP_FALLBACK: &str = "ap.spotify.com:443"; + +#[cfg(feature = "apresolve")] +mod apresolve; + +#[cfg(not(feature = "apresolve"))] +mod apresolve { + pub async fn apresolve(_: Option<&url::Url>, _: Option) -> String { + return super::AP_FALLBACK.into(); + } +} diff --git a/core/src/proxytunnel.rs b/core/src/proxytunnel.rs index 158d314f6..6f1587f06 100644 --- a/core/src/proxytunnel.rs +++ b/core/src/proxytunnel.rs @@ -2,16 +2,16 @@ use std::io; use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; -pub async fn connect( +pub async fn proxy_connect( mut proxy_connection: T, connect_host: &str, - connect_port: u16, + connect_port: &str, ) -> io::Result { let mut buffer = Vec::new(); buffer.extend_from_slice(b"CONNECT "); buffer.extend_from_slice(connect_host.as_bytes()); buffer.push(b':'); - buffer.extend_from_slice(connect_port.to_string().as_bytes()); + buffer.extend_from_slice(connect_port.as_bytes()); buffer.extend_from_slice(b" HTTP/1.1\r\n\r\n"); proxy_connection.write_all(buffer.as_ref()).await?; @@ -49,61 +49,7 @@ pub async fn connect( } if offset >= buffer.len() { - buffer.resize(buffer.len() * 2, 0); - } - } -} - -cfg_if! { - if #[cfg(feature = "apresolve")] { - use std::future::Future; - use std::net::{SocketAddr, ToSocketAddrs}; - use std::pin::Pin; - use std::task::Poll; - - use hyper::service::Service; - use hyper::Uri; - use tokio::net::TcpStream; - - #[derive(Clone)] - pub struct ProxyTunnel { - proxy_addr: SocketAddr, - } - - impl ProxyTunnel { - pub fn new(addr: T) -> io::Result { - let addr = addr.to_socket_addrs()?.next().ok_or_else(|| { - io::Error::new(io::ErrorKind::InvalidInput, "No socket address given") - })?; - Ok(Self { proxy_addr: addr }) - } - } - - impl Service for ProxyTunnel { - type Response = TcpStream; - type Error = io::Error; - type Future = Pin> + Send>>; - - fn poll_ready(&mut self, _: &mut std::task::Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } - - fn call(&mut self, url: Uri) -> Self::Future { - let proxy_addr = self.proxy_addr; - let fut = async move { - let host = url - .host() - .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Host is missing"))?; - let port = url - .port() - .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Port is missing"))?; - - let conn = TcpStream::connect(proxy_addr).await?; - connect(conn, host, port.as_u16()).await - }; - - Box::pin(fut) - } + buffer.resize(buffer.len() + 100, 0); } } } diff --git a/core/src/session.rs b/core/src/session.rs index 53bbabd8b..d7e478fa9 100644 --- a/core/src/session.rs +++ b/core/src/session.rs @@ -16,7 +16,7 @@ use thiserror::Error; use tokio::sync::mpsc; use tokio_stream::wrappers::UnboundedReceiverStream; -use crate::apresolve::apresolve_or_fallback; +use crate::apresolve::apresolve; use crate::audio_key::AudioKeyManager; use crate::authentication::Credentials; use crate::cache::Cache; @@ -67,10 +67,10 @@ impl Session { credentials: Credentials, cache: Option, ) -> Result { - let ap = apresolve_or_fallback(&config.proxy, &config.ap_port).await; + let ap = apresolve(config.proxy.as_ref(), config.ap_port).await; info!("Connecting to AP \"{}\"", ap); - let mut conn = connection::connect(ap, &config.proxy).await?; + let mut conn = connection::connect(ap, config.proxy.as_ref()).await?; let reusable_credentials = connection::authenticate(&mut conn, credentials, &config.device_id).await?; From 7c3d89112dc0cdb4a8105592268bbb6fe9f035f8 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Wed, 31 Mar 2021 20:05:32 +0200 Subject: [PATCH 61/75] Fix clippy warnings --- audio/src/passthrough_decoder.rs | 2 +- core/src/apresolve.rs | 4 ++-- core/src/config.rs | 18 +++++++++--------- core/src/connection/codec.rs | 12 ++++++------ core/src/connection/handshake.rs | 10 +++++----- core/src/connection/mod.rs | 4 ++-- core/src/diffie_hellman.rs | 8 ++++---- core/src/mercury/mod.rs | 6 +++--- core/src/mercury/types.rs | 22 +++++++++++----------- core/src/spotify_id.rs | 6 +++--- src/main.rs | 4 +++- 11 files changed, 49 insertions(+), 47 deletions(-) diff --git a/audio/src/passthrough_decoder.rs b/audio/src/passthrough_decoder.rs index d519baf87..e064cba38 100644 --- a/audio/src/passthrough_decoder.rs +++ b/audio/src/passthrough_decoder.rs @@ -110,7 +110,7 @@ impl AudioDecoder for PassthroughDecoder { fn next_packet(&mut self) -> Result, AudioError> { // write headers if we are (re)starting - if self.bos == false { + if !self.bos { self.wtr .write_packet( self.ident.clone(), diff --git a/core/src/apresolve.rs b/core/src/apresolve.rs index c954dab5b..85baba691 100644 --- a/core/src/apresolve.rs +++ b/core/src/apresolve.rs @@ -11,7 +11,7 @@ use super::AP_FALLBACK; const APRESOLVE_ENDPOINT: &str = "http://apresolve.spotify.com:80"; #[derive(Clone, Debug, Deserialize)] -struct APResolveData { +struct ApResolveData { ap_list: Vec, } @@ -41,7 +41,7 @@ async fn try_apresolve( }; let body = hyper::body::to_bytes(response.into_body()).await?; - let data: APResolveData = serde_json::from_slice(body.as_ref())?; + let data: ApResolveData = serde_json::from_slice(body.as_ref())?; let ap = if ap_port.is_some() || proxy.is_some() { data.ap_list.into_iter().find_map(|ap| { diff --git a/core/src/config.rs b/core/src/config.rs index a9e5ea2c3..9c70c25b5 100644 --- a/core/src/config.rs +++ b/core/src/config.rs @@ -29,9 +29,9 @@ pub enum DeviceType { Tablet = 2, Smartphone = 3, Speaker = 4, - TV = 5, - AVR = 6, - STB = 7, + Tv = 5, + Avr = 6, + Stb = 7, AudioDongle = 8, GameConsole = 9, CastAudio = 10, @@ -54,9 +54,9 @@ impl FromStr for DeviceType { "tablet" => Ok(Tablet), "smartphone" => Ok(Smartphone), "speaker" => Ok(Speaker), - "tv" => Ok(TV), - "avr" => Ok(AVR), - "stb" => Ok(STB), + "tv" => Ok(Tv), + "avr" => Ok(Avr), + "stb" => Ok(Stb), "audiodongle" => Ok(AudioDongle), "gameconsole" => Ok(GameConsole), "castaudio" => Ok(CastAudio), @@ -80,9 +80,9 @@ impl fmt::Display for DeviceType { Tablet => f.write_str("Tablet"), Smartphone => f.write_str("Smartphone"), Speaker => f.write_str("Speaker"), - TV => f.write_str("TV"), - AVR => f.write_str("AVR"), - STB => f.write_str("STB"), + Tv => f.write_str("TV"), + Avr => f.write_str("AVR"), + Stb => f.write_str("STB"), AudioDongle => f.write_str("AudioDongle"), GameConsole => f.write_str("GameConsole"), CastAudio => f.write_str("CastAudio"), diff --git a/core/src/connection/codec.rs b/core/src/connection/codec.rs index ead07b6ec..299220f64 100644 --- a/core/src/connection/codec.rs +++ b/core/src/connection/codec.rs @@ -13,7 +13,7 @@ enum DecodeState { Payload(u8, usize), } -pub struct APCodec { +pub struct ApCodec { encode_nonce: u32, encode_cipher: Shannon, @@ -22,9 +22,9 @@ pub struct APCodec { decode_state: DecodeState, } -impl APCodec { - pub fn new(send_key: &[u8], recv_key: &[u8]) -> APCodec { - APCodec { +impl ApCodec { + pub fn new(send_key: &[u8], recv_key: &[u8]) -> ApCodec { + ApCodec { encode_nonce: 0, encode_cipher: Shannon::new(send_key), @@ -35,7 +35,7 @@ impl APCodec { } } -impl Encoder<(u8, Vec)> for APCodec { +impl Encoder<(u8, Vec)> for ApCodec { type Error = io::Error; fn encode(&mut self, item: (u8, Vec), buf: &mut BytesMut) -> io::Result<()> { @@ -60,7 +60,7 @@ impl Encoder<(u8, Vec)> for APCodec { } } -impl Decoder for APCodec { +impl Decoder for ApCodec { type Item = (u8, Bytes); type Error = io::Error; diff --git a/core/src/connection/handshake.rs b/core/src/connection/handshake.rs index 67a786eee..879df67c9 100644 --- a/core/src/connection/handshake.rs +++ b/core/src/connection/handshake.rs @@ -7,16 +7,16 @@ use std::io; use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; use tokio_util::codec::{Decoder, Framed}; -use super::codec::APCodec; -use crate::diffie_hellman::DHLocalKeys; +use super::codec::ApCodec; +use crate::diffie_hellman::DhLocalKeys; use crate::protocol; use crate::protocol::keyexchange::{APResponseMessage, ClientHello, ClientResponsePlaintext}; use crate::util; pub async fn handshake( mut connection: T, -) -> io::Result> { - let local_keys = DHLocalKeys::random(&mut thread_rng()); +) -> io::Result> { + let local_keys = DhLocalKeys::random(&mut thread_rng()); let gc = local_keys.public_key(); let mut accumulator = client_hello(&mut connection, gc).await?; let message: APResponseMessage = recv_packet(&mut connection, &mut accumulator).await?; @@ -29,7 +29,7 @@ pub async fn handshake( let shared_secret = local_keys.shared_secret(&remote_key); let (challenge, send_key, recv_key) = compute_keys(&shared_secret, &accumulator); - let codec = APCodec::new(&send_key, &recv_key); + let codec = ApCodec::new(&send_key, &recv_key); client_response(&mut connection, challenge).await?; diff --git a/core/src/connection/mod.rs b/core/src/connection/mod.rs index 56d579bd6..d8a40129b 100644 --- a/core/src/connection/mod.rs +++ b/core/src/connection/mod.rs @@ -1,7 +1,7 @@ mod codec; mod handshake; -pub use self::codec::APCodec; +pub use self::codec::ApCodec; pub use self::handshake::handshake; use std::io::{self, ErrorKind}; @@ -19,7 +19,7 @@ use crate::protocol::keyexchange::{APLoginFailed, ErrorCode}; use crate::proxytunnel; use crate::version; -pub type Transport = Framed; +pub type Transport = Framed; fn login_error_message(code: &ErrorCode) -> &'static str { pub use ErrorCode::*; diff --git a/core/src/diffie_hellman.rs b/core/src/diffie_hellman.rs index 854480988..42d1fd9cf 100644 --- a/core/src/diffie_hellman.rs +++ b/core/src/diffie_hellman.rs @@ -17,19 +17,19 @@ pub static DH_PRIME: Lazy = Lazy::new(|| { ]) }); -pub struct DHLocalKeys { +pub struct DhLocalKeys { private_key: BigUint, public_key: BigUint, } -impl DHLocalKeys { - pub fn random(rng: &mut R) -> DHLocalKeys { +impl DhLocalKeys { + pub fn random(rng: &mut R) -> DhLocalKeys { let key_data = util::rand_vec(rng, 95); let private_key = BigUint::from_bytes_be(&key_data); let public_key = util::powm(&DH_GENERATOR, &private_key, &DH_PRIME); - DHLocalKeys { + DhLocalKeys { private_key, public_key, } diff --git a/core/src/mercury/mod.rs b/core/src/mercury/mod.rs index 1a68e15eb..b920e7e67 100644 --- a/core/src/mercury/mod.rs +++ b/core/src/mercury/mod.rs @@ -82,7 +82,7 @@ impl MercuryManager { pub fn get>(&self, uri: T) -> MercuryFuture { self.request(MercuryRequest { - method: MercuryMethod::GET, + method: MercuryMethod::Get, uri: uri.into(), content_type: None, payload: Vec::new(), @@ -91,7 +91,7 @@ impl MercuryManager { pub fn send>(&self, uri: T, data: Vec) -> MercuryFuture { self.request(MercuryRequest { - method: MercuryMethod::SEND, + method: MercuryMethod::Send, uri: uri.into(), content_type: None, payload: vec![data], @@ -109,7 +109,7 @@ impl MercuryManager { { let uri = uri.into(); let request = self.request(MercuryRequest { - method: MercuryMethod::SUB, + method: MercuryMethod::Sub, uri: uri.clone(), content_type: None, payload: Vec::new(), diff --git a/core/src/mercury/types.rs b/core/src/mercury/types.rs index 57cedce51..402a954c5 100644 --- a/core/src/mercury/types.rs +++ b/core/src/mercury/types.rs @@ -6,10 +6,10 @@ use crate::protocol; #[derive(Debug, PartialEq, Eq)] pub enum MercuryMethod { - GET, - SUB, - UNSUB, - SEND, + Get, + Sub, + Unsub, + Send, } #[derive(Debug)] @@ -33,10 +33,10 @@ pub struct MercuryError; impl ToString for MercuryMethod { fn to_string(&self) -> String { match *self { - MercuryMethod::GET => "GET", - MercuryMethod::SUB => "SUB", - MercuryMethod::UNSUB => "UNSUB", - MercuryMethod::SEND => "SEND", + MercuryMethod::Get => "GET", + MercuryMethod::Sub => "SUB", + MercuryMethod::Unsub => "UNSUB", + MercuryMethod::Send => "SEND", } .to_owned() } @@ -45,9 +45,9 @@ impl ToString for MercuryMethod { impl MercuryMethod { pub fn command(&self) -> u8 { match *self { - MercuryMethod::GET | MercuryMethod::SEND => 0xb2, - MercuryMethod::SUB => 0xb3, - MercuryMethod::UNSUB => 0xb4, + MercuryMethod::Get | MercuryMethod::Send => 0xb2, + MercuryMethod::Sub => 0xb3, + MercuryMethod::Unsub => 0xb4, } } } diff --git a/core/src/spotify_id.rs b/core/src/spotify_id.rs index 09d109758..801c6ac95 100644 --- a/core/src/spotify_id.rs +++ b/core/src/spotify_id.rs @@ -18,9 +18,9 @@ impl From<&str> for SpotifyAudioType { } } -impl Into<&str> for SpotifyAudioType { - fn into(self) -> &'static str { - match self { +impl From for &str { + fn from(audio_type: SpotifyAudioType) -> &'static str { + match audio_type { SpotifyAudioType::Track => "track", SpotifyAudioType::Podcast => "episode", SpotifyAudioType::NonPlayable => "unknown", diff --git a/src/main.rs b/src/main.rs index 1f67793ea..cd2a78613 100644 --- a/src/main.rs +++ b/src/main.rs @@ -345,7 +345,9 @@ fn setup(args: &[String]) -> Setup { .map(|port| port.parse::().unwrap()) .unwrap_or(0); - let name = matches.opt_str("name").unwrap_or("Librespot".to_string()); + let name = matches + .opt_str("name") + .unwrap_or_else(|| "Librespot".to_string()); let credentials = { let cached_credentials = cache.as_ref().and_then(Cache::credentials); From 11ce29077e661100fa71580dbcb9dda6a4950932 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Thu, 1 Apr 2021 18:10:42 +0200 Subject: [PATCH 62/75] Fix formatting --- core/src/authentication.rs | 7 ++----- examples/get_token.rs | 4 +++- examples/play.rs | 10 +++++----- examples/playlist_tracks.rs | 4 +++- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/core/src/authentication.rs b/core/src/authentication.rs index 2992abcdf..db787bbe2 100644 --- a/core/src/authentication.rs +++ b/core/src/authentication.rs @@ -31,13 +31,10 @@ impl Credentials { /// ### Example /// ```rust /// use librespot_core::authentication::Credentials; - /// + /// /// let creds = Credentials::with_password("my account", "my password"); /// ``` - pub fn with_password( - username: impl Into, - password: impl Into, - ) -> Credentials { + pub fn with_password(username: impl Into, password: impl Into) -> Credentials { Credentials { username: username.into(), auth_type: AuthenticationType::AUTHENTICATION_USER_PASS, diff --git a/examples/get_token.rs b/examples/get_token.rs index 15b97bcb9..636155e04 100644 --- a/examples/get_token.rs +++ b/examples/get_token.rs @@ -20,7 +20,9 @@ async fn main() { println!("Connecting.."); let credentials = Credentials::with_password(&args[1], &args[2]); - let session = Session::connect(session_config, credentials, None).await.unwrap(); + let session = Session::connect(session_config, credentials, None) + .await + .unwrap(); println!( "Token: {:#?}", diff --git a/examples/play.rs b/examples/play.rs index 9b1988a6a..b4f2b68e6 100644 --- a/examples/play.rs +++ b/examples/play.rs @@ -4,8 +4,8 @@ use librespot::core::authentication::Credentials; use librespot::core::config::SessionConfig; use librespot::core::session::Session; use librespot::core::spotify_id::SpotifyId; -use librespot::playback::config::PlayerConfig; use librespot::playback::audio_backend; +use librespot::playback::config::PlayerConfig; use librespot::playback::player::Player; #[tokio::main] @@ -25,11 +25,11 @@ async fn main() { let backend = audio_backend::find(None).unwrap(); println!("Connecting .."); - let session = Session::connect(session_config, credentials, None).await.unwrap(); + let session = Session::connect(session_config, credentials, None) + .await + .unwrap(); - let (mut player, _) = Player::new(player_config, session, None, move || { - backend(None) - }); + let (mut player, _) = Player::new(player_config, session, None, move || backend(None)); player.load(track, true, 0); diff --git a/examples/playlist_tracks.rs b/examples/playlist_tracks.rs index 7bd95ae25..e96938cbc 100644 --- a/examples/playlist_tracks.rs +++ b/examples/playlist_tracks.rs @@ -25,7 +25,9 @@ async fn main() { let plist_uri = SpotifyId::from_base62(uri_parts[2]).unwrap(); - let session = Session::connect(session_config, credentials, None).await.unwrap(); + let session = Session::connect(session_config, credentials, None) + .await + .unwrap(); let plist = Playlist::get(&session, plist_uri).await.unwrap(); println!("{:?}", plist); From 7ddb1a20bb21ceae17821bba2f3714377d8b1cc3 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Wed, 10 Mar 2021 22:55:40 +0100 Subject: [PATCH 63/75] Reuse librespot-core's Diffie Hellman in discovery --- Cargo.lock | 1 - connect/Cargo.toml | 1 - connect/src/discovery.rs | 27 +++++++++------------------ 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a43939d90..023add286 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1344,7 +1344,6 @@ dependencies = [ "librespot-playback", "librespot-protocol", "log", - "num-bigint", "protobuf", "rand", "serde", diff --git a/connect/Cargo.toml b/connect/Cargo.toml index b03de885f..1331b6279 100644 --- a/connect/Cargo.toml +++ b/connect/Cargo.toml @@ -16,7 +16,6 @@ futures-util = { version = "0.3", default_features = false } hmac = "0.10" hyper = { version = "0.14", features = ["server", "http1", "tcp"] } log = "0.4" -num-bigint = "0.3" protobuf = "~2.14.0" rand = "0.8" serde = { version = "1.0", features = ["derive"] } diff --git a/connect/src/discovery.rs b/connect/src/discovery.rs index 7bb36a200..383035cc5 100644 --- a/connect/src/discovery.rs +++ b/connect/src/discovery.rs @@ -5,7 +5,6 @@ use futures_core::Stream; use hmac::{Hmac, Mac, NewMac}; use hyper::service::{make_service_fn, service_fn}; use hyper::{Body, Method, Request, Response, StatusCode}; -use num_bigint::BigUint; use serde_json::json; use sha1::{Digest, Sha1}; use tokio::sync::{mpsc, oneshot}; @@ -15,8 +14,7 @@ use dns_sd::DNSService; use librespot_core::authentication::Credentials; use librespot_core::config::ConnectConfig; -use librespot_core::diffie_hellman::{DH_GENERATOR, DH_PRIME}; -use librespot_core::util; +use librespot_core::diffie_hellman::DhLocalKeys; use std::borrow::Cow; use std::collections::BTreeMap; @@ -34,8 +32,7 @@ struct Discovery(Arc); struct DiscoveryInner { config: ConnectConfig, device_id: String, - private_key: BigUint, - public_key: BigUint, + keys: DhLocalKeys, tx: mpsc::UnboundedSender, } @@ -46,15 +43,10 @@ impl Discovery { ) -> (Discovery, mpsc::UnboundedReceiver) { let (tx, rx) = mpsc::unbounded_channel(); - let key_data = util::rand_vec(&mut rand::thread_rng(), 95); - let private_key = BigUint::from_bytes_be(&key_data); - let public_key = util::powm(&DH_GENERATOR, &private_key, &DH_PRIME); - let discovery = Discovery(Arc::new(DiscoveryInner { config, device_id, - private_key, - public_key, + keys: DhLocalKeys::random(&mut rand::thread_rng()), tx, })); @@ -62,8 +54,7 @@ impl Discovery { } fn handle_get_info(&self, _: BTreeMap, Cow<'_, str>>) -> Response { - let public_key = self.0.public_key.to_bytes_be(); - let public_key = base64::encode(&public_key); + let public_key = base64::encode(&self.0.keys.public_key()); let result = json!({ "status": 101, @@ -98,16 +89,16 @@ impl Discovery { let encrypted_blob = base64::decode(encrypted_blob.as_bytes()).unwrap(); - let client_key = base64::decode(client_key.as_bytes()).unwrap(); - let client_key = BigUint::from_bytes_be(&client_key); - - let shared_key = util::powm(&client_key, &self.0.private_key, &DH_PRIME); + let shared_key = self + .0 + .keys + .shared_secret(&base64::decode(client_key.as_bytes()).unwrap()); let iv = &encrypted_blob[0..16]; let encrypted = &encrypted_blob[16..encrypted_blob.len() - 20]; let cksum = &encrypted_blob[encrypted_blob.len() - 20..encrypted_blob.len()]; - let base_key = Sha1::digest(&shared_key.to_bytes_be()); + let base_key = Sha1::digest(&shared_key); let base_key = &base_key[..16]; let checksum_key = { From 9378ae5b6f5ff5a6700e3882058a69a18d547d70 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Thu, 18 Mar 2021 17:52:39 +0100 Subject: [PATCH 64/75] Bump num-bigint dependency --- Cargo.lock | 4 ++-- core/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 023add286..3991775fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1633,9 +1633,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e9a41747ae4633fce5adffb4d2e81ffc5e89593cb19917f8fb2cc5ff76507bf" +checksum = "4e0d047c1062aa51e256408c560894e5251f08925980e53cf1aa5bd00eec6512" dependencies = [ "autocfg", "num-integer", diff --git a/core/Cargo.toml b/core/Cargo.toml index 7aabb1b06..4e9b03c9d 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -25,7 +25,7 @@ http = "0.2" hyper = { version = "0.14", optional = true, features = ["client", "tcp", "http1"] } hyper-proxy = { version = "0.9.1", optional = true, default-features = false } log = "0.4" -num-bigint = "0.3" +num-bigint = "0.4" num-integer = "0.1" num-traits = "0.2" once_cell = "1.5.2" From e688e7e886791b98e5af0271f5ec552c6a699cca Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Thu, 18 Mar 2021 17:51:50 +0100 Subject: [PATCH 65/75] Almost eliminate util module --- Cargo.lock | 3 +++ connect/Cargo.toml | 1 + connect/src/spirc.rs | 7 +++-- core/Cargo.toml | 3 ++- core/src/connection/handshake.rs | 8 +++--- core/src/diffie_hellman.rs | 38 +++++++++++++++++--------- core/src/lib.rs | 2 ++ core/src/mercury/mod.rs | 18 ++++++++++--- core/src/util.rs | 46 -------------------------------- 9 files changed, 59 insertions(+), 67 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3991775fc..9b66a41e4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1335,6 +1335,7 @@ dependencies = [ "base64", "block-modes", "dns-sd", + "form_urlencoded", "futures-core", "futures-util", "hmac", @@ -1363,6 +1364,7 @@ dependencies = [ "byteorder", "bytes", "env_logger", + "form_urlencoded", "futures-core", "futures-util", "hmac", @@ -1640,6 +1642,7 @@ dependencies = [ "autocfg", "num-integer", "num-traits", + "rand", ] [[package]] diff --git a/connect/Cargo.toml b/connect/Cargo.toml index 1331b6279..052cf6a57 100644 --- a/connect/Cargo.toml +++ b/connect/Cargo.toml @@ -11,6 +11,7 @@ edition = "2018" aes-ctr = "0.6" base64 = "0.13" block-modes = "0.7" +form_urlencoded = "1.0" futures-core = "0.3" futures-util = { version = "0.3", default_features = false } hmac = "0.10" diff --git a/connect/src/spirc.rs b/connect/src/spirc.rs index 1a7f64ec2..4fcb025a5 100644 --- a/connect/src/spirc.rs +++ b/connect/src/spirc.rs @@ -7,7 +7,6 @@ use crate::core::config::{ConnectConfig, VolumeCtrl}; use crate::core::mercury::{MercuryError, MercurySender}; use crate::core::session::Session; use crate::core::spotify_id::{SpotifyAudioType, SpotifyId, SpotifyIdError}; -use crate::core::util::url_encode; use crate::core::util::SeqGenerator; use crate::core::version; use crate::playback::mixer::Mixer; @@ -244,6 +243,10 @@ fn volume_to_mixer(volume: u16, volume_ctrl: &VolumeCtrl) -> u16 { } } +fn url_encode(bytes: impl AsRef<[u8]>) -> String { + form_urlencoded::byte_serialize(bytes.as_ref()).collect() +} + impl Spirc { pub fn new( config: ConnectConfig, @@ -256,7 +259,7 @@ impl Spirc { let ident = session.device_id().to_owned(); // Uri updated in response to issue #288 - debug!("canonical_username: {}", url_encode(&session.username())); + debug!("canonical_username: {}", &session.username()); let uri = format!("hm://remote/user/{}/", url_encode(&session.username())); let subscription = Box::pin( diff --git a/core/Cargo.toml b/core/Cargo.toml index 4e9b03c9d..29f4f3329 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -17,6 +17,7 @@ aes = "0.6" base64 = "0.13" byteorder = "1.4" bytes = "1.0" +form_urlencoded = "1.0" futures-core = { version = "0.3", default-features = false } futures-util = { version = "0.3", default-features = false, features = ["alloc", "bilock", "unstable", "sink"] } hmac = "0.10" @@ -25,7 +26,7 @@ http = "0.2" hyper = { version = "0.14", optional = true, features = ["client", "tcp", "http1"] } hyper-proxy = { version = "0.9.1", optional = true, default-features = false } log = "0.4" -num-bigint = "0.4" +num-bigint = { version = "0.4", features = ["rand"] } num-integer = "0.1" num-traits = "0.2" once_cell = "1.5.2" diff --git a/core/src/connection/handshake.rs b/core/src/connection/handshake.rs index 879df67c9..6f802ab55 100644 --- a/core/src/connection/handshake.rs +++ b/core/src/connection/handshake.rs @@ -1,7 +1,7 @@ use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; use hmac::{Hmac, Mac, NewMac}; use protobuf::{self, Message}; -use rand::thread_rng; +use rand::{thread_rng, RngCore}; use sha1::Sha1; use std::io; use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; @@ -11,7 +11,6 @@ use super::codec::ApCodec; use crate::diffie_hellman::DhLocalKeys; use crate::protocol; use crate::protocol::keyexchange::{APResponseMessage, ClientHello, ClientResponsePlaintext}; -use crate::util; pub async fn handshake( mut connection: T, @@ -40,6 +39,9 @@ async fn client_hello(connection: &mut T, gc: Vec) -> io::Result> where T: AsyncWrite + Unpin, { + let mut client_nonce = vec![0; 0x10]; + thread_rng().fill_bytes(&mut client_nonce); + let mut packet = ClientHello::new(); packet .mut_build_info() @@ -59,7 +61,7 @@ where .mut_login_crypto_hello() .mut_diffie_hellman() .set_server_keys_known(1); - packet.set_client_nonce(util::rand_vec(&mut thread_rng(), 0x10)); + packet.set_client_nonce(client_nonce); packet.set_padding(vec![0x1e]); let mut buffer = vec![0, 4]; diff --git a/core/src/diffie_hellman.rs b/core/src/diffie_hellman.rs index 42d1fd9cf..57caa029c 100644 --- a/core/src/diffie_hellman.rs +++ b/core/src/diffie_hellman.rs @@ -1,11 +1,11 @@ -use num_bigint::BigUint; +use num_bigint::{BigUint, RandBigInt}; +use num_integer::Integer; +use num_traits::{One, Zero}; use once_cell::sync::Lazy; -use rand::Rng; +use rand::{CryptoRng, Rng}; -use crate::util; - -pub static DH_GENERATOR: Lazy = Lazy::new(|| BigUint::from_bytes_be(&[0x02])); -pub static DH_PRIME: Lazy = Lazy::new(|| { +static DH_GENERATOR: Lazy = Lazy::new(|| BigUint::from_bytes_be(&[0x02])); +static DH_PRIME: Lazy = Lazy::new(|| { BigUint::from_bytes_be(&[ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34, 0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, @@ -17,17 +17,31 @@ pub static DH_PRIME: Lazy = Lazy::new(|| { ]) }); +fn powm(base: &BigUint, exp: &BigUint, modulus: &BigUint) -> BigUint { + let mut base = base.clone(); + let mut exp = exp.clone(); + let mut result: BigUint = One::one(); + + while !exp.is_zero() { + if exp.is_odd() { + result = (result * &base) % modulus; + } + exp >>= 1; + base = (&base * &base) % modulus; + } + + result +} + pub struct DhLocalKeys { private_key: BigUint, public_key: BigUint, } impl DhLocalKeys { - pub fn random(rng: &mut R) -> DhLocalKeys { - let key_data = util::rand_vec(rng, 95); - - let private_key = BigUint::from_bytes_be(&key_data); - let public_key = util::powm(&DH_GENERATOR, &private_key, &DH_PRIME); + pub fn random(rng: &mut R) -> DhLocalKeys { + let private_key = rng.gen_biguint(95 * 8); + let public_key = powm(&DH_GENERATOR, &private_key, &DH_PRIME); DhLocalKeys { private_key, @@ -40,7 +54,7 @@ impl DhLocalKeys { } pub fn shared_secret(&self, remote_key: &[u8]) -> Vec { - let shared_key = util::powm( + let shared_key = powm( &BigUint::from_bytes_be(remote_key), &self.private_key, &DH_PRIME, diff --git a/core/src/lib.rs b/core/src/lib.rs index 320967f70..bb3e21d59 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -14,12 +14,14 @@ pub mod cache; pub mod channel; pub mod config; mod connection; +#[doc(hidden)] pub mod diffie_hellman; pub mod keymaster; pub mod mercury; mod proxytunnel; pub mod session; pub mod spotify_id; +#[doc(hidden)] pub mod util; pub mod version; diff --git a/core/src/mercury/mod.rs b/core/src/mercury/mod.rs index b920e7e67..ef04e9854 100644 --- a/core/src/mercury/mod.rs +++ b/core/src/mercury/mod.rs @@ -10,7 +10,6 @@ use bytes::Bytes; use tokio::sync::{mpsc, oneshot}; use crate::protocol; -use crate::util::url_encode; use crate::util::SeqGenerator; mod types; @@ -199,7 +198,7 @@ impl MercuryManager { let header: protocol::mercury::Header = protobuf::parse_from_bytes(&header_data).unwrap(); let response = MercuryResponse { - uri: url_encode(header.get_uri()), + uri: header.get_uri().to_string(), status_code: header.get_status_code(), payload: pending.parts, }; @@ -214,8 +213,21 @@ impl MercuryManager { } else if cmd == 0xb5 { self.lock(|inner| { let mut found = false; + + // TODO: This is just a workaround to make utf-8 encoded usernames work. + // A better solution would be to use an uri struct and urlencode it directly + // before sending while saving the subscription under its unencoded form. + let mut uri_split = response.uri.split('/'); + + let encoded_uri = std::iter::once(uri_split.next().unwrap().to_string()) + .chain(uri_split.map(|component| { + form_urlencoded::byte_serialize(component.as_bytes()).collect::() + })) + .collect::>() + .join("/"); + inner.subscriptions.retain(|&(ref prefix, ref sub)| { - if response.uri.starts_with(prefix) { + if encoded_uri.starts_with(prefix) { found = true; // if send fails, remove from list of subs diff --git a/core/src/util.rs b/core/src/util.rs index c55d96016..df9ea714f 100644 --- a/core/src/util.rs +++ b/core/src/util.rs @@ -1,50 +1,4 @@ -use num_bigint::BigUint; -use num_integer::Integer; -use num_traits::{One, Zero}; -use rand::Rng; use std::mem; -use std::ops::{Mul, Rem, Shr}; - -pub fn rand_vec(rng: &mut G, size: usize) -> Vec { - ::std::iter::repeat(()) - .map(|()| rng.gen()) - .take(size) - .collect() -} - -pub fn url_encode(inp: &str) -> String { - let mut encoded = String::new(); - - for c in inp.as_bytes().iter() { - match *c as char { - 'A'..='Z' | 'a'..='z' | '0'..='9' | '-' | '_' | '.' | '~' | ':' | '/' => { - encoded.push(*c as char) - } - c => encoded.push_str(format!("%{:02X}", c as u32).as_str()), - }; - } - - encoded -} - -pub fn powm(base: &BigUint, exp: &BigUint, modulus: &BigUint) -> BigUint { - let mut base = base.clone(); - let mut exp = exp.clone(); - let mut result: BigUint = One::one(); - - while !exp.is_zero() { - if exp.is_odd() { - result = result.mul(&base).rem(modulus); - } - exp = exp.shr(1); - base = (&base).mul(&base).rem(modulus); - } - - result -} - -pub trait ReadSeek: ::std::io::Read + ::std::io::Seek {} -impl ReadSeek for T {} pub trait Seq { fn next(&self) -> Self; From cb8c9c2afa6880c95ee29f1e403a7f291aaf6013 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Thu, 1 Apr 2021 18:20:42 +0200 Subject: [PATCH 66/75] Enable apresolve always in binary Librespot-connect uses hyper anyway, so no one needs to disable it only to reduce the number of dependencies. Furthermore, when using another backend, people will use --no-default-features and will forget to enable the apresolve feature again. --- Cargo.toml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8f3e44c28..7939b76ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,7 @@ version = "0.1.6" [dependencies.librespot-core] path = "core" version = "0.1.6" +features = ["apresolve"] [dependencies.librespot-metadata] path = "metadata" @@ -58,8 +59,6 @@ url = "2.1" sha-1 = "0.9" [features] -apresolve = ["librespot-core/apresolve"] - alsa-backend = ["librespot-playback/alsa-backend"] portaudio-backend = ["librespot-playback/portaudio-backend"] pulseaudio-backend = ["librespot-playback/pulseaudio-backend"] @@ -75,7 +74,7 @@ with-lewton = ["librespot-audio/with-lewton"] # with-dns-sd = ["librespot-connect/with-dns-sd"] -default = ["rodio-backend", "apresolve", "with-lewton"] +default = ["rodio-backend", "with-lewton"] [package.metadata.deb] maintainer = "librespot-org" From b7350b71da72251b57c9449a94b722b0a1420b01 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Fri, 9 Apr 2021 16:38:43 +0200 Subject: [PATCH 67/75] Restore previous feature flags Some of the feature flags librespot uses are not really additive but rather mutual exclusive. A previous attempt to improve the situation had other drawbacks, so it's better to postpone a decision and restore the old behaviour. --- Cargo.toml | 5 ++--- audio/Cargo.toml | 3 +-- audio/src/lib.rs | 15 +++------------ connect/Cargo.toml | 4 +--- 4 files changed, 7 insertions(+), 20 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7939b76ce..14e33a83f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,11 +70,10 @@ gstreamer-backend = ["librespot-playback/gstreamer-backend"] with-tremor = ["librespot-audio/with-tremor"] with-vorbis = ["librespot-audio/with-vorbis"] -with-lewton = ["librespot-audio/with-lewton"] -# with-dns-sd = ["librespot-connect/with-dns-sd"] +with-dns-sd = ["librespot-connect/with-dns-sd"] -default = ["rodio-backend", "with-lewton"] +default = ["rodio-backend"] [package.metadata.deb] maintainer = "librespot-org" diff --git a/audio/Cargo.toml b/audio/Cargo.toml index d8c0eea28..5dec789f3 100644 --- a/audio/Cargo.toml +++ b/audio/Cargo.toml @@ -15,17 +15,16 @@ aes-ctr = "0.6" byteorder = "1.4" bytes = "1.0" cfg-if = "1" +lewton = "0.10" log = "0.4" futures-util = { version = "0.3", default_features = false } ogg = "0.8" tempfile = "3.1" tokio = { version = "1", features = ["sync"] } -lewton = { version = "0.10", optional = true } librespot-tremor = { version = "0.2.0", optional = true } vorbis = { version ="0.0.14", optional = true } [features] -with-lewton = ["lewton"] with-tremor = ["librespot-tremor"] with-vorbis = ["vorbis"] diff --git a/audio/src/lib.rs b/audio/src/lib.rs index 80f1097d5..35ec4dd7c 100644 --- a/audio/src/lib.rs +++ b/audio/src/lib.rs @@ -8,22 +8,13 @@ mod fetch; use cfg_if::cfg_if; -#[cfg(any( - all(feature = "with-lewton", feature = "with-tremor"), - all(feature = "with-vorbis", feature = "with-tremor"), - all(feature = "with-lewton", feature = "with-vorbis") -))] -compile_error!("Cannot use two decoders at the same time."); - cfg_if! { - if #[cfg(feature = "with-lewton")] { - mod lewton_decoder; - pub use lewton_decoder::{VorbisDecoder, VorbisError}; - } else if #[cfg(any(feature = "with-tremor", feature = "with-vorbis"))] { + if #[cfg(any(feature = "with-tremor", feature = "with-vorbis"))] { mod libvorbis_decoder; pub use crate::libvorbis_decoder::{VorbisDecoder, VorbisError}; } else { - compile_error!("Must choose a vorbis decoder."); + mod lewton_decoder; + pub use lewton_decoder::{VorbisDecoder, VorbisError}; } } diff --git a/connect/Cargo.toml b/connect/Cargo.toml index 052cf6a57..689efd3c2 100644 --- a/connect/Cargo.toml +++ b/connect/Cargo.toml @@ -16,6 +16,7 @@ futures-core = "0.3" futures-util = { version = "0.3", default_features = false } hmac = "0.10" hyper = { version = "0.14", features = ["server", "http1", "tcp"] } +libmdns = "0.6" log = "0.4" protobuf = "~2.14.0" rand = "0.8" @@ -27,7 +28,6 @@ tokio-stream = { version = "0.1" } url = "2.1" dns-sd = { version = "0.1.3", optional = true } -libmdns = { version = "0.6", optional = true } [dependencies.librespot-core] path = "../core" @@ -42,7 +42,5 @@ path = "../protocol" version = "0.1.6" [features] -with-libmdns = ["libmdns"] with-dns-sd = ["dns-sd"] -default = ["with-libmdns"] From 9a3a6668568bb1169a50f6cbc9e7cd1964d21916 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Fri, 9 Apr 2021 16:43:05 +0200 Subject: [PATCH 68/75] Bump MSRV to 1.45 --- .github/workflows/test.yml | 2 +- COMPILING.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9d1250f97..907a6eb71 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -41,7 +41,7 @@ jobs: matrix: os: [ubuntu-latest] toolchain: - - 1.41.1 # MSRV (Minimum supported rust version) + - 1.45 # MSRV (Minimum supported rust version) - stable - beta experimental: [false] diff --git a/COMPILING.md b/COMPILING.md index 4320cdbbc..539dc698a 100644 --- a/COMPILING.md +++ b/COMPILING.md @@ -13,7 +13,7 @@ curl https://sh.rustup.rs -sSf | sh Follow any prompts it gives you to install Rust. Once that’s done, Rust's standard tools should be setup and ready to use. -*Note: The current minimum required Rust version at the time of writing is 1.41, you can find the current minimum version specified in the `.github/workflow/test.yml` file.* +*Note: The current minimum required Rust version at the time of writing is 1.45, you can find the current minimum version specified in the `.github/workflow/test.yml` file.* #### Additional Rust tools - `rustfmt` To ensure a consistent codebase, we utilise [`rustfmt`](https://github.com/rust-lang/rustfmt), which is installed by default with `rustup` these days, else it can be installed manually with: From 5435ab3270fc889e2c217803906f775f5d36f5d0 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Thu, 1 Apr 2021 18:41:01 +0200 Subject: [PATCH 69/75] Fix compile errors in backends fe37186 added the restriction that `Sink`s must be `Send`. It turned out later that this restrictions was unnecessary, and since some `Sink`s aren't `Send` yet, this restriction is lifted again. librespot-org/librespot#601 refactored the `RodioSink` in order to make it `Send`. These changes are partly reverted in favour of the initial simpler design. Furthermore, there were some compile errors in the gstreamer backend which are hereby fixed. --- playback/src/audio_backend/gstreamer.rs | 15 +++++++------ playback/src/audio_backend/mod.rs | 4 ++-- playback/src/audio_backend/rodio.rs | 29 +++++-------------------- playback/src/player.rs | 4 ++-- src/main.rs | 2 +- 5 files changed, 18 insertions(+), 36 deletions(-) diff --git a/playback/src/audio_backend/gstreamer.rs b/playback/src/audio_backend/gstreamer.rs index 4678bfb07..e2b52d744 100644 --- a/playback/src/audio_backend/gstreamer.rs +++ b/playback/src/audio_backend/gstreamer.rs @@ -1,7 +1,9 @@ use super::{Open, Sink}; use crate::audio::AudioPacket; + use gst::prelude::*; -use gst::*; +use gstreamer as gst; +use gstreamer_app as gst_app; use zerocopy::*; use std::sync::mpsc::{sync_channel, SyncSender}; @@ -52,14 +54,13 @@ impl Open for GstreamerSink { thread::spawn(move || { for data in rx { let buffer = bufferpool.acquire_buffer(None); - if !buffer.is_err() { - let mut okbuffer = buffer.unwrap(); - let mutbuf = okbuffer.make_mut(); + if let Ok(mut buffer) = buffer { + let mutbuf = buffer.make_mut(); mutbuf.set_size(data.len()); mutbuf .copy_from_slice(0, data.as_bytes()) .expect("Failed to copy from slice"); - let _eat = appsrc.push_buffer(okbuffer); + let _eat = appsrc.push_buffer(buffer); } } }); @@ -69,8 +70,8 @@ impl Open for GstreamerSink { let watch_mainloop = thread_mainloop.clone(); bus.add_watch(move |_, msg| { match msg.view() { - MessageView::Eos(..) => watch_mainloop.quit(), - MessageView::Error(err) => { + gst::MessageView::Eos(..) => watch_mainloop.quit(), + gst::MessageView::Error(err) => { println!( "Error from {:?}: {} ({:?})", err.get_src().map(|s| s.get_path_string()), diff --git a/playback/src/audio_backend/mod.rs b/playback/src/audio_backend/mod.rs index c816a6d66..5fa518ee1 100644 --- a/playback/src/audio_backend/mod.rs +++ b/playback/src/audio_backend/mod.rs @@ -11,9 +11,9 @@ pub trait Sink { fn write(&mut self, packet: &AudioPacket) -> io::Result<()>; } -pub type SinkBuilder = fn(Option) -> Box; +pub type SinkBuilder = fn(Option) -> Box; -fn mk_sink(device: Option) -> Box { +fn mk_sink(device: Option) -> Box { Box::new(S::open(device)) } diff --git a/playback/src/audio_backend/rodio.rs b/playback/src/audio_backend/rodio.rs index 338dfbbfe..8e4482114 100644 --- a/playback/src/audio_backend/rodio.rs +++ b/playback/src/audio_backend/rodio.rs @@ -1,5 +1,4 @@ use std::process::exit; -use std::{convert::Infallible, sync::mpsc}; use std::{io, thread, time}; use cpal::traits::{DeviceTrait, HostTrait}; @@ -15,12 +14,12 @@ use crate::audio::AudioPacket; compile_error!("Rodio JACK backend is currently only supported on linux."); #[cfg(feature = "rodio-backend")] -pub fn mk_rodio(device: Option) -> Box { +pub fn mk_rodio(device: Option) -> Box { Box::new(open(cpal::default_host(), device)) } #[cfg(feature = "rodiojack-backend")] -pub fn mk_rodiojack(device: Option) -> Box { +pub fn mk_rodiojack(device: Option) -> Box { Box::new(open( cpal::host_from_id(cpal::HostId::Jack).unwrap(), device, @@ -43,8 +42,7 @@ pub enum RodioError { pub struct RodioSink { rodio_sink: rodio::Sink, - // will produce a TryRecvError on the receiver side when it is dropped. - _close_tx: mpsc::SyncSender, + _stream: rodio::OutputStream, } fn list_formats(device: &rodio::Device) { @@ -152,29 +150,12 @@ fn create_sink( pub fn open(host: cpal::Host, device: Option) -> RodioSink { debug!("Using rodio sink with cpal host: {}", host.id().name()); - let (sink_tx, sink_rx) = mpsc::sync_channel(1); - let (close_tx, close_rx) = mpsc::sync_channel(1); - - std::thread::spawn(move || match create_sink(&host, device) { - Ok((sink, stream)) => { - sink_tx.send(Ok(sink)).unwrap(); - - close_rx.recv().unwrap_err(); // This will fail as soon as the sender is dropped - debug!("drop rodio::OutputStream"); - drop(stream); - } - Err(e) => { - sink_tx.send(Err(e)).unwrap(); - } - }); - - // Instead of the second `unwrap`, better error handling could be introduced - let sink = sink_rx.recv().unwrap().unwrap(); + let (sink, stream) = create_sink(&host, device).unwrap(); debug!("Rodio sink was created"); RodioSink { rodio_sink: sink, - _close_tx: close_tx, + _stream: stream, } } diff --git a/playback/src/player.rs b/playback/src/player.rs index 0d2380e73..497a4a115 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -50,7 +50,7 @@ struct PlayerInternal { state: PlayerState, preload: PlayerPreload, - sink: Box, + sink: Box, sink_status: SinkStatus, sink_event_callback: Option, audio_filter: Option>, @@ -242,7 +242,7 @@ impl Player { sink_builder: F, ) -> (Player, PlayerEventChannel) where - F: FnOnce() -> Box + Send + 'static, + F: FnOnce() -> Box + Send + 'static, { let (cmd_tx, cmd_rx) = mpsc::unbounded_channel(); let (event_sender, event_receiver) = mpsc::unbounded_channel(); diff --git a/src/main.rs b/src/main.rs index cd2a78613..54057aed5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -105,7 +105,7 @@ fn print_version() { #[derive(Clone)] struct Setup { - backend: fn(Option) -> Box, + backend: fn(Option) -> Box, device: Option, mixer: fn(Option) -> Box, From 690e0d2e10f942d1243ea2bae1ca902ffc322cb6 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Fri, 2 Apr 2021 14:44:42 +0200 Subject: [PATCH 70/75] Add simple tests to librespot-core The first test checks whether apresolve works. A second test tries to create a Spotify sessions with fake credentials and asserts that an error is returned. --- core/src/apresolve.rs | 23 +++++++++++++++++++++ core/tests/connect.rs | 48 +++++++++++++++---------------------------- 2 files changed, 39 insertions(+), 32 deletions(-) diff --git a/core/src/apresolve.rs b/core/src/apresolve.rs index 85baba691..b11e275f2 100644 --- a/core/src/apresolve.rs +++ b/core/src/apresolve.rs @@ -66,3 +66,26 @@ pub async fn apresolve(proxy: Option<&Url>, ap_port: Option) -> String { AP_FALLBACK.into() }) } + +#[cfg(test)] +mod test { + use std::net::ToSocketAddrs; + + use super::try_apresolve; + + #[tokio::test] + async fn test_apresolve() { + let ap = try_apresolve(None, None).await.unwrap(); + + // Assert that the result contains a valid host and port + ap.to_socket_addrs().unwrap().next().unwrap(); + } + + #[tokio::test] + async fn test_apresolve_port_443() { + let ap = try_apresolve(None, Some(443)).await.unwrap(); + + let port = ap.to_socket_addrs().unwrap().next().unwrap().port(); + assert_eq!(port, 443); + } +} diff --git a/core/tests/connect.rs b/core/tests/connect.rs index b7bc29f81..4f1dbe6b8 100644 --- a/core/tests/connect.rs +++ b/core/tests/connect.rs @@ -1,34 +1,18 @@ -use librespot_core::*; +use librespot_core::authentication::Credentials; +use librespot_core::config::SessionConfig; +use librespot_core::session::Session; -// TODO: test is broken -// #[cfg(test)] -// mod tests { -// use super::*; -// // Test AP Resolve -// use apresolve::apresolve_or_fallback; -// #[tokio::test] -// async fn test_ap_resolve() { -// env_logger::init(); -// let ap = apresolve_or_fallback(&None, &None).await; -// println!("AP: {:?}", ap); -// } +#[tokio::test] +async fn test_connection() { + let result = Session::connect( + SessionConfig::default(), + Credentials::with_password("test", "test"), + None, + ) + .await; -// // Test connect -// use authentication::Credentials; -// use config::SessionConfig; -// #[tokio::test] -// async fn test_connection() -> Result<(), Box> { -// println!("Running connection test"); -// let ap = apresolve_or_fallback(&None, &None).await; -// let credentials = Credentials::with_password(String::from("test"), String::from("test")); -// let session_config = SessionConfig::default(); -// let proxy = None; - -// println!("Connecting to AP \"{}\"", ap); -// let mut connection = connection::connect(ap, &proxy).await?; -// let rc = connection::authenticate(&mut connection, credentials, &session_config.device_id) -// .await?; -// println!("Authenticated as \"{}\"", rc.username); -// Ok(()) -// } -// } + match result { + Ok(_) => panic!("Authentication succeeded despite of bad credentials."), + Err(e) => assert_eq!(e.to_string(), "Login failed with reason: Bad credentials"), + }; +} From ff499825e0ce509b5d49669ac328e4ba85073da4 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Fri, 9 Apr 2021 17:00:56 +0200 Subject: [PATCH 71/75] Add missing feature flag to tokio --- audio/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/audio/Cargo.toml b/audio/Cargo.toml index 5dec789f3..2cd801a12 100644 --- a/audio/Cargo.toml +++ b/audio/Cargo.toml @@ -20,7 +20,7 @@ log = "0.4" futures-util = { version = "0.3", default_features = false } ogg = "0.8" tempfile = "3.1" -tokio = { version = "1", features = ["sync"] } +tokio = { version = "1", features = ["sync", "macros"] } librespot-tremor = { version = "0.2.0", optional = true } vorbis = { version ="0.0.14", optional = true } From 317e5864729e07f9d7b2150d928f95c2424d8ad2 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Fri, 9 Apr 2021 17:01:30 +0200 Subject: [PATCH 72/75] Improve CI Run the tests and add build for Windows. --- .github/workflows/test.yml | 137 ++++++++++++++++++++++++++++--------- 1 file changed, 104 insertions(+), 33 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 907a6eb71..f06445e60 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,36 +4,49 @@ name: test on: push: branches: [master, dev] - paths: ['**.rs', '**.toml', '**.lock', '**.yml'] + paths: + [ + "**.rs", + "Cargo.toml", + "/Cargo.lock", + "/rustfmt.toml", + "/.github/workflows", + ] pull_request: - branches: [master, dev] - paths: ['**.rs', '**.toml', '**.lock', '**.yml'] + paths: + [ + "**.rs", + "Cargo.toml", + "/Cargo.lock", + "/rustfmt.toml", + "/.github/workflows", + ] + schedule: + # Run CI every week + - cron: "00 01 * * 0" + +env: + RUST_BACKTRACE: 1 jobs: fmt: - name: 'Rust: format check' - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - # Only run the formatting check for stable - include: - - os: ubuntu-latest - toolchain: stable + name: rustfmt + runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v2 - name: Install toolchain uses: actions-rs/toolchain@v1 with: - # Use default profile to get rustfmt - profile: default - toolchain: ${{ matrix.toolchain }} + profile: minimal + toolchain: stable override: true - - run: cargo fmt --verbose --all -- --check + components: rustfmt + - run: cargo fmt --all -- --check - test: + test-linux: needs: fmt + name: cargo +${{ matrix.toolchain }} build (${{ matrix.os }}) runs-on: ${{ matrix.os }} continue-on-error: ${{ matrix.experimental }} strategy: @@ -45,7 +58,7 @@ jobs: - stable - beta experimental: [false] - # Ignore failures in nightly, not ideal, but necessary + # Ignore failures in nightly include: - os: ubuntu-latest toolchain: nightly @@ -53,12 +66,19 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v2 + - name: Install toolchain uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: ${{ matrix.toolchain }} override: true + + - name: Get Rustc version + id: get-rustc-version + run: echo "::set-output name=version::$(rustc -V)" + shell: bash + - name: Cache Rust dependencies uses: actions/cache@v2 with: @@ -67,21 +87,65 @@ jobs: ~/.cargo/registry/cache ~/.cargo/git target - key: ${{ runner.os }}-build-${{ hashFiles('**/Cargo.lock') }} + key: ${{ runner.os }}-${{ steps.get-rustc-version.outputs.version }}-${{ hashFiles('**/Cargo.lock') }} + - name: Install developer package dependencies - run: sudo apt-get update && sudo apt-get install libpulse-dev portaudio19-dev libasound2-dev libsdl2-dev gstreamer1.0-dev libgstreamer-plugins-base1.0-dev - - run: cargo build --locked --no-default-features - - run: cargo build --locked --examples - - run: cargo build --locked --no-default-features --features "with-tremor" - - run: cargo build --locked --no-default-features --features "with-vorbis" - - run: cargo build --locked --no-default-features --features "alsa-backend" - - run: cargo build --locked --no-default-features --features "portaudio-backend" - - run: cargo build --locked --no-default-features --features "pulseaudio-backend" - - run: cargo build --locked --no-default-features --features "jackaudio-backend" - - run: cargo build --locked --no-default-features --features "rodiojack-backend" - - run: cargo build --locked --no-default-features --features "rodio-backend" - - run: cargo build --locked --no-default-features --features "sdl-backend" - - run: cargo build --locked --no-default-features --features "gstreamer-backend" + run: sudo apt-get update && sudo apt-get install libpulse-dev portaudio19-dev libasound2-dev libsdl2-dev gstreamer1.0-dev libgstreamer-plugins-base1.0-dev libavahi-compat-libdnssd-dev + + - run: cargo build --workspace --examples + - run: cargo test --workspace + + - run: cargo install cargo-hack + - run: cargo hack --workspace --remove-dev-deps + - run: cargo build -p librespot-core --no-default-features + - run: cargo build -p librespot-core + - run: cargo hack build --each-feature -p librespot-audio + - run: cargo build -p librespot-connect + - run: cargo build -p librespot-connect --no-default-features --features with-dns-sd + - run: cargo hack build --locked --each-feature + + test-windows: + needs: fmt + name: cargo build (${{ matrix.os }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [windows-latest] + toolchain: [stable] + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Install toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ matrix.toolchain }} + profile: minimal + override: true + + - name: Get Rustc version + id: get-rustc-version + run: echo "::set-output name=version::$(rustc -V)" + shell: bash + + - name: Cache Rust dependencies + uses: actions/cache@v2 + with: + path: | + ~/.cargo/registry/index + ~/.cargo/registry/cache + ~/.cargo/git + target + key: ${{ runner.os }}-${{ steps.get-rustc-version.outputs.version }}-${{ hashFiles('**/Cargo.lock') }} + + - run: cargo build --workspace --examples + - run: cargo test --workspace + + - run: cargo install cargo-hack + - run: cargo hack --workspace --remove-dev-deps + - run: cargo build --no-default-features + - run: cargo build test-cross-arm: needs: fmt @@ -97,6 +161,7 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v2 + - name: Install toolchain uses: actions-rs/toolchain@v1 with: @@ -104,6 +169,12 @@ jobs: target: ${{ matrix.target }} toolchain: ${{ matrix.toolchain }} override: true + + - name: Get Rustc version + id: get-rustc-version + run: echo "::set-output name=version::$(rustc -V)" + shell: bash + - name: Cache Rust dependencies uses: actions/cache@v2 with: @@ -112,7 +183,7 @@ jobs: ~/.cargo/registry/cache ~/.cargo/git target - key: ${{ runner.os }}-build-${{ hashFiles('**/Cargo.lock') }} + key: ${{ runner.os }}-${{ matrix.target }}-${{ steps.get-rustc-version.outputs.version }}-${{ hashFiles('**/Cargo.lock') }} - name: Install cross run: cargo install cross || true - name: Build From a576194b0ecf7ec825e5a474d69fcde8bc9b0400 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Sat, 10 Apr 2021 13:31:42 +0200 Subject: [PATCH 73/75] Fix bug in rodio backend --- playback/src/audio_backend/rodio.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/playback/src/audio_backend/rodio.rs b/playback/src/audio_backend/rodio.rs index 98494dba1..035cd3287 100644 --- a/playback/src/audio_backend/rodio.rs +++ b/playback/src/audio_backend/rodio.rs @@ -199,8 +199,6 @@ impl Sink for RodioSink { } _ => unreachable!(), }; - let source = rodio::buffer::SamplesBuffer::new(2, 44100, packet.samples()); - self.rodio_sink.append(source); // Chunk sizes seem to be about 256 to 3000 ish items long. // Assuming they're on average 1628 then a half second buffer is: From b4f9ae31e2832ba6c0bd753eeb36902dd2cb07cc Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Sat, 10 Apr 2021 14:06:41 +0200 Subject: [PATCH 74/75] Fix clippy warnings --- audio/src/convert.rs | 31 +++++++++++-------------- audio/src/lib.rs | 3 +-- playback/src/audio_backend/alsa.rs | 8 +++---- playback/src/audio_backend/jackaudio.rs | 2 +- playback/src/audio_backend/mod.rs | 10 ++++---- playback/src/audio_backend/portaudio.rs | 7 +++--- playback/src/audio_backend/rodio.rs | 4 ++-- playback/src/audio_backend/sdl.rs | 6 ++--- playback/src/config.rs | 2 +- playback/src/mixer/alsamixer.rs | 7 +++--- playback/src/player.rs | 6 ++--- src/main.rs | 4 ++-- 12 files changed, 41 insertions(+), 49 deletions(-) diff --git a/audio/src/convert.rs b/audio/src/convert.rs index e291c804e..450910b0b 100644 --- a/audio/src/convert.rs +++ b/audio/src/convert.rs @@ -36,24 +36,21 @@ macro_rules! convert_samples_to { }; } -pub struct SamplesConverter {} -impl SamplesConverter { - pub fn to_s32(samples: &[f32]) -> Vec { - convert_samples_to!(i32, samples) - } +pub fn to_s32(samples: &[f32]) -> Vec { + convert_samples_to!(i32, samples) +} - pub fn to_s24(samples: &[f32]) -> Vec { - convert_samples_to!(i32, samples, 8) - } +pub fn to_s24(samples: &[f32]) -> Vec { + convert_samples_to!(i32, samples, 8) +} - pub fn to_s24_3(samples: &[f32]) -> Vec { - Self::to_s32(samples) - .iter() - .map(|sample| i24::pcm_from_i32(*sample)) - .collect() - } +pub fn to_s24_3(samples: &[f32]) -> Vec { + to_s32(samples) + .iter() + .map(|sample| i24::pcm_from_i32(*sample)) + .collect() +} - pub fn to_s16(samples: &[f32]) -> Vec { - convert_samples_to!(i16, samples) - } +pub fn to_s16(samples: &[f32]) -> Vec { + convert_samples_to!(i16, samples) } diff --git a/audio/src/lib.rs b/audio/src/lib.rs index e0a4858c0..b587f038c 100644 --- a/audio/src/lib.rs +++ b/audio/src/lib.rs @@ -3,7 +3,7 @@ #[macro_use] extern crate log; -mod convert; +pub mod convert; mod decrypt; mod fetch; @@ -24,7 +24,6 @@ pub use passthrough_decoder::{PassthroughDecoder, PassthroughError}; mod range_set; -pub use convert::{i24, SamplesConverter}; pub use decrypt::AudioDecrypt; pub use fetch::{AudioFile, StreamLoaderController}; pub use fetch::{ diff --git a/playback/src/audio_backend/alsa.rs b/playback/src/audio_backend/alsa.rs index 1d5518785..54fed319d 100644 --- a/playback/src/audio_backend/alsa.rs +++ b/playback/src/audio_backend/alsa.rs @@ -87,7 +87,7 @@ impl Open for AlsaSink { Self { pcm: None, - format: format, + format, device: name, buffer: vec![], } @@ -146,7 +146,7 @@ impl SinkAsBytes for AlsaSink { .extend_from_slice(&data[processed_data..processed_data + data_to_buffer]); processed_data += data_to_buffer; if self.buffer.len() == self.buffer.capacity() { - self.write_buf().expect("could not append to buffer"); + self.write_buf(); self.buffer.clear(); } } @@ -156,14 +156,12 @@ impl SinkAsBytes for AlsaSink { } impl AlsaSink { - fn write_buf(&mut self) -> io::Result<()> { + fn write_buf(&mut self) { let pcm = self.pcm.as_mut().unwrap(); let io = pcm.io_bytes(); match io.writei(&self.buffer) { Ok(_) => (), Err(err) => pcm.try_recover(err, false).unwrap(), }; - - Ok(()) } } diff --git a/playback/src/audio_backend/jackaudio.rs b/playback/src/audio_backend/jackaudio.rs index b38c9014f..aca2edd2b 100644 --- a/playback/src/audio_backend/jackaudio.rs +++ b/playback/src/audio_backend/jackaudio.rs @@ -47,7 +47,7 @@ impl Open for JackSink { } info!("Using JACK sink with format {:?}", AudioFormat::F32); - let client_name = client_name.unwrap_or("librespot".to_string()); + let client_name = client_name.unwrap_or_else(|| "librespot".to_string()); let (client, _status) = Client::new(&client_name[..], ClientOptions::NO_START_SERVER).unwrap(); let ch_r = client.register_port("out_0", AudioOut::default()).unwrap(); diff --git a/playback/src/audio_backend/mod.rs b/playback/src/audio_backend/mod.rs index 24f5f855d..72659f196 100644 --- a/playback/src/audio_backend/mod.rs +++ b/playback/src/audio_backend/mod.rs @@ -26,25 +26,25 @@ fn mk_sink(device: Option, format: AudioFormat macro_rules! sink_as_bytes { () => { fn write(&mut self, packet: &AudioPacket) -> io::Result<()> { - use crate::audio::{i24, SamplesConverter}; + use crate::audio::convert::{self, i24}; use zerocopy::AsBytes; match packet { AudioPacket::Samples(samples) => match self.format { AudioFormat::F32 => self.write_bytes(samples.as_bytes()), AudioFormat::S32 => { - let samples_s32: &[i32] = &SamplesConverter::to_s32(samples); + let samples_s32: &[i32] = &convert::to_s32(samples); self.write_bytes(samples_s32.as_bytes()) } AudioFormat::S24 => { - let samples_s24: &[i32] = &SamplesConverter::to_s24(samples); + let samples_s24: &[i32] = &convert::to_s24(samples); self.write_bytes(samples_s24.as_bytes()) } AudioFormat::S24_3 => { - let samples_s24_3: &[i24] = &SamplesConverter::to_s24_3(samples); + let samples_s24_3: &[i24] = &convert::to_s24_3(samples); self.write_bytes(samples_s24_3.as_bytes()) } AudioFormat::S16 => { - let samples_s16: &[i16] = &SamplesConverter::to_s16(samples); + let samples_s16: &[i16] = &convert::to_s16(samples); self.write_bytes(samples_s16.as_bytes()) } }, diff --git a/playback/src/audio_backend/portaudio.rs b/playback/src/audio_backend/portaudio.rs index 5faff6ca4..234a9af6a 100644 --- a/playback/src/audio_backend/portaudio.rs +++ b/playback/src/audio_backend/portaudio.rs @@ -1,8 +1,7 @@ use super::{Open, Sink}; -use crate::audio::{AudioPacket, SamplesConverter}; +use crate::audio::{convert, AudioPacket}; use crate::config::AudioFormat; use crate::player::{NUM_CHANNELS, SAMPLE_RATE}; -use portaudio_rs; use portaudio_rs::device::{get_default_output_index, DeviceIndex, DeviceInfo}; use portaudio_rs::stream::*; use std::io; @@ -157,11 +156,11 @@ impl<'a> Sink for PortAudioSink<'a> { write_sink!(ref mut stream, samples) } Self::S32(stream, _parameters) => { - let samples_s32: &[i32] = &SamplesConverter::to_s32(samples); + let samples_s32: &[i32] = &convert::to_s32(samples); write_sink!(ref mut stream, samples_s32) } Self::S16(stream, _parameters) => { - let samples_s16: &[i16] = &SamplesConverter::to_s16(samples); + let samples_s16: &[i16] = &convert::to_s16(samples); write_sink!(ref mut stream, samples_s16) } }; diff --git a/playback/src/audio_backend/rodio.rs b/playback/src/audio_backend/rodio.rs index 035cd3287..65436a326 100644 --- a/playback/src/audio_backend/rodio.rs +++ b/playback/src/audio_backend/rodio.rs @@ -5,7 +5,7 @@ use cpal::traits::{DeviceTrait, HostTrait}; use thiserror::Error; use super::Sink; -use crate::audio::{AudioPacket, SamplesConverter}; +use crate::audio::{convert, AudioPacket}; use crate::config::AudioFormat; use crate::player::{NUM_CHANNELS, SAMPLE_RATE}; @@ -189,7 +189,7 @@ impl Sink for RodioSink { self.rodio_sink.append(source); } AudioFormat::S16 => { - let samples_s16: &[i16] = &SamplesConverter::to_s16(samples); + let samples_s16: &[i16] = &convert::to_s16(samples); let source = rodio::buffer::SamplesBuffer::new( NUM_CHANNELS as u16, SAMPLE_RATE, diff --git a/playback/src/audio_backend/sdl.rs b/playback/src/audio_backend/sdl.rs index 0a3fd433b..29566533b 100644 --- a/playback/src/audio_backend/sdl.rs +++ b/playback/src/audio_backend/sdl.rs @@ -1,5 +1,5 @@ use super::{Open, Sink}; -use crate::audio::{AudioPacket, SamplesConverter}; +use crate::audio::{convert, AudioPacket}; use crate::config::AudioFormat; use crate::player::{NUM_CHANNELS, SAMPLE_RATE}; use sdl2::audio::{AudioQueue, AudioSpecDesired}; @@ -97,12 +97,12 @@ impl Sink for SdlSink { queue.queue(samples) } Self::S32(queue) => { - let samples_s32: &[i32] = &SamplesConverter::to_s32(samples); + let samples_s32: &[i32] = &convert::to_s32(samples); drain_sink!(queue, AudioFormat::S32.size()); queue.queue(samples_s32) } Self::S16(queue) => { - let samples_s16: &[i16] = &SamplesConverter::to_s16(samples); + let samples_s16: &[i16] = &convert::to_s16(samples); drain_sink!(queue, AudioFormat::S16.size()); queue.queue(samples_s16) } diff --git a/playback/src/config.rs b/playback/src/config.rs index 95c970923..f8f028933 100644 --- a/playback/src/config.rs +++ b/playback/src/config.rs @@ -1,4 +1,4 @@ -use crate::audio::i24; +use crate::audio::convert::i24; use std::convert::TryFrom; use std::mem; use std::str::FromStr; diff --git a/playback/src/mixer/alsamixer.rs b/playback/src/mixer/alsamixer.rs index d9dbe311f..5e0a963f4 100644 --- a/playback/src/mixer/alsamixer.rs +++ b/playback/src/mixer/alsamixer.rs @@ -33,13 +33,12 @@ impl AlsaMixer { let mixer = alsa::mixer::Mixer::new(&config.card, false)?; let sid = alsa::mixer::SelemId::new(&config.mixer, config.index); - let selem = mixer.find_selem(&sid).expect( - format!( + let selem = mixer.find_selem(&sid).unwrap_or_else(|| { + panic!( "Couldn't find simple mixer control for {},{}", &config.mixer, &config.index, ) - .as_str(), - ); + }); let (min, max) = selem.get_playback_volume_range(); let (min_db, max_db) = selem.get_playback_db_range(); let hw_mix = selem diff --git a/playback/src/player.rs b/playback/src/player.rs index f53abbfbe..3f0778f9a 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -206,11 +206,11 @@ pub struct NormalisationData { impl NormalisationData { pub fn db_to_ratio(db: f32) -> f32 { - return f32::powf(10.0, db / DB_VOLTAGE_RATIO); + f32::powf(10.0, db / DB_VOLTAGE_RATIO) } pub fn ratio_to_db(ratio: f32) -> f32 { - return ratio.log10() * DB_VOLTAGE_RATIO; + ratio.log10() * DB_VOLTAGE_RATIO } fn parse_from_file(mut file: T) -> io::Result { @@ -1161,7 +1161,7 @@ impl PlayerInternal { } if self.config.normalisation - && (normalisation_factor != 1.0 + && (f32::abs(normalisation_factor - 1.0) < f32::EPSILON || self.config.normalisation_method != NormalisationMethod::Basic) { for sample in data.iter_mut() { diff --git a/src/main.rs b/src/main.rs index 4abe4e5e9..318e1757a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -322,7 +322,7 @@ fn setup(args: &[String]) -> Setup { .opt_str("format") .as_ref() .map(|format| AudioFormat::try_from(format).expect("Invalid output format")) - .unwrap_or(AudioFormat::default()); + .unwrap_or_default(); let device = matches.opt_str("device"); if device == Some("?".into()) { @@ -470,7 +470,7 @@ fn setup(args: &[String]) -> Setup { bitrate, gapless: !matches.opt_present("disable-gapless"), normalisation: matches.opt_present("enable-volume-normalisation"), - normalisation_method: normalisation_method, + normalisation_method, normalisation_type: gain_type, normalisation_pregain: matches .opt_str("normalisation-pregain") From 3e9aee1d46e9bc90d2b7c321a5f8d7c823c98788 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Sat, 10 Apr 2021 15:08:39 +0200 Subject: [PATCH 75/75] Renamed variable --- src/main.rs | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/main.rs b/src/main.rs index 318e1757a..78e7e2f96 100644 --- a/src/main.rs +++ b/src/main.rs @@ -128,7 +128,7 @@ struct Setup { emit_sink_events: bool, } -fn setup(args: &[String]) -> Setup { +fn get_setup(args: &[String]) -> Setup { let mut opts = getopts::Options::new(); opts.optopt( "c", @@ -553,7 +553,7 @@ async fn main() { } let args: Vec = std::env::args().collect(); - let setupp = setup(&args); + let setup = get_setup(&args); let mut last_credentials = None; let mut spirc: Option = None; @@ -563,23 +563,23 @@ async fn main() { let mut discovery = None; let mut connecting: Pin>> = Box::pin(future::pending()); - if setupp.enable_discovery { - let config = setupp.connect_config.clone(); - let device_id = setupp.session_config.device_id.clone(); + if setup.enable_discovery { + let config = setup.connect_config.clone(); + let device_id = setup.session_config.device_id.clone(); discovery = Some( - librespot_connect::discovery::discovery(config, device_id, setupp.zeroconf_port) + librespot_connect::discovery::discovery(config, device_id, setup.zeroconf_port) .unwrap(), ); } - if let Some(credentials) = setupp.credentials { + if let Some(credentials) = setup.credentials { last_credentials = Some(credentials.clone()); connecting = Box::pin( Session::connect( - setupp.session_config.clone(), + setup.session_config.clone(), credentials, - setupp.cache.clone(), + setup.cache.clone(), ) .fuse(), ); @@ -602,9 +602,9 @@ async fn main() { } connecting = Box::pin(Session::connect( - setupp.session_config.clone(), + setup.session_config.clone(), credentials, - setupp.cache.clone(), + setup.cache.clone(), ).fuse()); }, None => { @@ -615,22 +615,22 @@ async fn main() { }, session = &mut connecting, if !connecting.is_terminated() => match session { Ok(session) => { - let mixer_config = setupp.mixer_config.clone(); - let mixer = (setupp.mixer)(Some(mixer_config)); - let player_config = setupp.player_config.clone(); - let connect_config = setupp.connect_config.clone(); + let mixer_config = setup.mixer_config.clone(); + let mixer = (setup.mixer)(Some(mixer_config)); + let player_config = setup.player_config.clone(); + let connect_config = setup.connect_config.clone(); let audio_filter = mixer.get_audio_filter(); - let format = setupp.format; - let backend = setupp.backend; - let device = setupp.device.clone(); + let format = setup.format; + let backend = setup.backend; + let device = setup.device.clone(); let (player, event_channel) = Player::new(player_config, session.clone(), audio_filter, move || { (backend)(device, format) }); - if setupp.emit_sink_events { - if let Some(player_event_program) = setupp.player_event_program.clone() { + if setup.emit_sink_events { + if let Some(player_event_program) = setup.player_event_program.clone() { player.set_sink_event_callback(Some(Box::new(move |sink_status| { match emit_sink_event(sink_status, &player_event_program) { Ok(e) if e.success() => (), @@ -676,16 +676,16 @@ async fn main() { auto_connect_times.push(Instant::now()); connecting = Box::pin(Session::connect( - setupp.session_config.clone(), + setup.session_config.clone(), credentials, - setupp.cache.clone(), + setup.cache.clone(), ).fuse()); } } }, event = async { player_event_channel.as_mut().unwrap().recv().await }, if player_event_channel.is_some() => match event { Some(event) => { - if let Some(program) = &setupp.player_event_program { + if let Some(program) = &setup.player_event_program { if let Some(child) = run_program_on_events(event, program) { let mut child = child.expect("program failed to start");