mirror of
https://github.com/librespot-org/librespot.git
synced 2024-12-18 17:11:53 +00:00
Convert discovery to hyper 1.x
This commit is contained in:
parent
6a4053e871
commit
da0deb1de6
4 changed files with 86 additions and 50 deletions
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -942,7 +942,7 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9"
|
checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.21.7",
|
"base64",
|
||||||
"bytes",
|
"bytes",
|
||||||
"headers-core",
|
"headers-core",
|
||||||
"http",
|
"http",
|
||||||
|
@ -1459,7 +1459,7 @@ name = "librespot-core"
|
||||||
version = "0.5.0-dev"
|
version = "0.5.0-dev"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes",
|
"aes",
|
||||||
"base64 0.21.7",
|
"base64",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"bytes",
|
"bytes",
|
||||||
"data-encoding",
|
"data-encoding",
|
||||||
|
@ -1513,7 +1513,8 @@ name = "librespot-discovery"
|
||||||
version = "0.5.0-dev"
|
version = "0.5.0-dev"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes",
|
"aes",
|
||||||
"base64 0.21.7",
|
"base64",
|
||||||
|
"bytes",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"ctr",
|
"ctr",
|
||||||
"dns-sd",
|
"dns-sd",
|
||||||
|
@ -1523,6 +1524,7 @@ dependencies = [
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"hex",
|
"hex",
|
||||||
"hmac",
|
"hmac",
|
||||||
|
"http-body-util",
|
||||||
"hyper",
|
"hyper",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"libmdns",
|
"libmdns",
|
||||||
|
@ -2455,7 +2457,7 @@ version = "2.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3c333bb734fcdedcea57de1602543590f545f127dc8b533324318fd492c5c70b"
|
checksum = "3c333bb734fcdedcea57de1602543590f545f127dc8b533324318fd492c5c70b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.21.7",
|
"base64",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
aes = "0.8"
|
aes = "0.8"
|
||||||
base64 = "0.21"
|
base64 = "0.21"
|
||||||
|
bytes = "1"
|
||||||
cfg-if = "1.0"
|
cfg-if = "1.0"
|
||||||
ctr = "0.9"
|
ctr = "0.9"
|
||||||
dns-sd = { version = "0.1.3", optional = true }
|
dns-sd = { version = "0.1.3", optional = true }
|
||||||
|
@ -18,7 +19,9 @@ form_urlencoded = "1.0"
|
||||||
futures-core = "0.3"
|
futures-core = "0.3"
|
||||||
futures-util = "0.3"
|
futures-util = "0.3"
|
||||||
hmac = "0.12"
|
hmac = "0.12"
|
||||||
hyper = { version = "0.14", features = ["http1", "server", "tcp", "backports", "deprecated"] }
|
hyper = { version = "1.3", features = ["http1"] }
|
||||||
|
hyper-util = { version = "0.1", features = ["server-auto", "server-graceful", "service"] }
|
||||||
|
http-body-util = "0.1.1"
|
||||||
libmdns = "0.8"
|
libmdns = "0.8"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
|
|
|
@ -124,7 +124,7 @@ impl Builder {
|
||||||
pub fn launch(self) -> Result<Discovery, Error> {
|
pub fn launch(self) -> Result<Discovery, Error> {
|
||||||
let mut port = self.port;
|
let mut port = self.port;
|
||||||
let name = self.server_config.name.clone().into_owned();
|
let name = self.server_config.name.clone().into_owned();
|
||||||
let server = DiscoveryServer::new(self.server_config, &mut port)??;
|
let server = DiscoveryServer::new(self.server_config, &mut port)?;
|
||||||
let _zeroconf_ip = self.zeroconf_ip;
|
let _zeroconf_ip = self.zeroconf_ip;
|
||||||
let svc;
|
let svc;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
collections::BTreeMap,
|
collections::BTreeMap,
|
||||||
convert::Infallible,
|
convert::Infallible,
|
||||||
net::{Ipv4Addr, SocketAddr},
|
net::{Ipv4Addr, SocketAddr, TcpListener},
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
task::{Context, Poll},
|
task::{Context, Poll},
|
||||||
|
@ -11,13 +11,16 @@ use std::{
|
||||||
use aes::cipher::{KeyIvInit, StreamCipher};
|
use aes::cipher::{KeyIvInit, StreamCipher};
|
||||||
use base64::engine::general_purpose::STANDARD as BASE64;
|
use base64::engine::general_purpose::STANDARD as BASE64;
|
||||||
use base64::engine::Engine as _;
|
use base64::engine::Engine as _;
|
||||||
|
use bytes::Bytes;
|
||||||
use futures_core::Stream;
|
use futures_core::Stream;
|
||||||
use futures_util::{FutureExt, TryFutureExt};
|
use futures_util::{FutureExt, TryFutureExt};
|
||||||
use hmac::{Hmac, Mac};
|
use hmac::{Hmac, Mac};
|
||||||
|
use http_body_util::{BodyExt, Full};
|
||||||
use hyper::{
|
use hyper::{
|
||||||
body::HttpBody, service::{make_service_fn, service_fn}, Body, Method, Request, Response, StatusCode
|
body::Incoming, Method, Request, Response, StatusCode
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use hyper_util::{rt::TokioIo, server::graceful::GracefulShutdown};
|
||||||
use log::{debug, error, warn};
|
use log::{debug, error, warn};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use sha1::{Digest, Sha1};
|
use sha1::{Digest, Sha1};
|
||||||
|
@ -62,7 +65,7 @@ impl RequestHandler {
|
||||||
(discovery, rx)
|
(discovery, rx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_get_info(&self) -> Response<hyper::Body> {
|
fn handle_get_info(&self) -> Response<Full<Bytes>> {
|
||||||
let public_key = BASE64.encode(self.keys.public_key());
|
let public_key = BASE64.encode(self.keys.public_key());
|
||||||
let device_type: &str = self.config.device_type.into();
|
let device_type: &str = self.config.device_type.into();
|
||||||
let mut active_user = String::new();
|
let mut active_user = String::new();
|
||||||
|
@ -106,11 +109,11 @@ impl RequestHandler {
|
||||||
// - "deviceAPI_isGroup": False
|
// - "deviceAPI_isGroup": False
|
||||||
})
|
})
|
||||||
.to_string();
|
.to_string();
|
||||||
|
let body = Bytes::from(body);
|
||||||
Response::new(Body::from(body))
|
Response::new(Full::new(body))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_add_user(&self, params: &Params<'_>) -> Result<Response<hyper::Body>, Error> {
|
fn handle_add_user(&self, params: &Params<'_>) -> Result<Response<Full<Bytes>>, Error> {
|
||||||
let username_key = "userName";
|
let username_key = "userName";
|
||||||
let username = params
|
let username = params
|
||||||
.get(username_key)
|
.get(username_key)
|
||||||
|
@ -170,7 +173,8 @@ impl RequestHandler {
|
||||||
});
|
});
|
||||||
|
|
||||||
let body = result.to_string();
|
let body = result.to_string();
|
||||||
return Ok(Response::new(Body::from(body)));
|
let body = Bytes::from(body);
|
||||||
|
return Ok(Response::new(Full::new(body)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let decrypted = {
|
let decrypted = {
|
||||||
|
@ -192,10 +196,11 @@ impl RequestHandler {
|
||||||
});
|
});
|
||||||
|
|
||||||
let body = result.to_string();
|
let body = result.to_string();
|
||||||
Ok(Response::new(Body::from(body)))
|
let body = Bytes::from(body);
|
||||||
|
Ok(Response::new(Full::new(body)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn not_found(&self) -> Response<hyper::Body> {
|
fn not_found(&self) -> Response<Full<Bytes>> {
|
||||||
let mut res = Response::default();
|
let mut res = Response::default();
|
||||||
*res.status_mut() = StatusCode::NOT_FOUND;
|
*res.status_mut() = StatusCode::NOT_FOUND;
|
||||||
res
|
res
|
||||||
|
@ -203,8 +208,8 @@ impl RequestHandler {
|
||||||
|
|
||||||
async fn handle(
|
async fn handle(
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
request: Request<Body>,
|
request: Request<Incoming>,
|
||||||
) -> Result<hyper::Result<Response<Body>>, Error> {
|
) -> Result<hyper::Result<Response<Full<Bytes>>>, Error> {
|
||||||
let mut params = Params::new();
|
let mut params = Params::new();
|
||||||
|
|
||||||
let (parts, body) = request.into_parts();
|
let (parts, body) = request.into_parts();
|
||||||
|
@ -238,52 +243,78 @@ pub struct DiscoveryServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DiscoveryServer {
|
impl DiscoveryServer {
|
||||||
pub fn new(config: Config, port: &mut u16) -> Result<hyper::Result<Self>, Error> {
|
pub fn new(config: Config, port: &mut u16) -> Result<Self, Error> {
|
||||||
let (discovery, cred_rx) = RequestHandler::new(config);
|
let (discovery, cred_rx) = RequestHandler::new(config);
|
||||||
let discovery = Arc::new(discovery);
|
let address = SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), *port);
|
||||||
|
|
||||||
let (close_tx, close_rx) = oneshot::channel();
|
let (close_tx, close_rx) = oneshot::channel();
|
||||||
|
|
||||||
let address = SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), *port);
|
let listener = match TcpListener::bind(address) {
|
||||||
|
Ok(listener) => listener,
|
||||||
let make_service = make_service_fn(move |_| {
|
Err(e) => {
|
||||||
let discovery = discovery.clone();
|
warn!("Discovery server failed to start: {e}");
|
||||||
async move {
|
return Err(e.into());
|
||||||
Ok::<_, hyper::Error>(service_fn(move |request| {
|
|
||||||
discovery
|
|
||||||
.clone()
|
|
||||||
.handle(request)
|
|
||||||
.inspect_err(|e| error!("could not handle discovery request: {}", e))
|
|
||||||
.and_then(|x| async move { Ok(x) })
|
|
||||||
.map(Result::unwrap) // guaranteed by `and_then` above
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
let server = hyper::Server::try_bind(&address)?.serve(make_service);
|
listener.set_nonblocking(true)?;
|
||||||
|
let listener = tokio::net::TcpListener::from_std(listener)?;
|
||||||
|
|
||||||
*port = server.local_addr().port();
|
match listener.local_addr() {
|
||||||
debug!("Zeroconf server listening on 0.0.0.0:{}", *port);
|
Ok(addr) => {
|
||||||
|
*port = addr.port();
|
||||||
|
debug!("Zeroconf server listening on 0.0.0.0:{}", *port);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
warn!("Discovery server failed to start: {e}");
|
||||||
|
return Err(e.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tokio::spawn(async {
|
|
||||||
let result = server
|
tokio::spawn(async move {
|
||||||
.with_graceful_shutdown(async {
|
let discovery = Arc::new(discovery);
|
||||||
if let Err(e) = close_rx.await {
|
|
||||||
debug!("unable to close discovery Rx channel completely: {e}");
|
let server = hyper::server::conn::http1::Builder::new();
|
||||||
|
let graceful = GracefulShutdown::new();
|
||||||
|
let mut close_rx = std::pin::pin!(close_rx);
|
||||||
|
loop {
|
||||||
|
tokio::select! {
|
||||||
|
Ok((stream, _)) = listener.accept() => {
|
||||||
|
let io = TokioIo::new(stream);
|
||||||
|
let discovery = discovery.clone();
|
||||||
|
|
||||||
|
let svc = hyper::service::service_fn(move |request| {
|
||||||
|
discovery
|
||||||
|
.clone()
|
||||||
|
.handle(request)
|
||||||
|
.inspect_err(|e| error!("could not handle discovery request: {}", e))
|
||||||
|
.and_then(|x| async move { Ok(x) })
|
||||||
|
.map(Result::unwrap) // guaranteed by `and_then` above
|
||||||
|
});
|
||||||
|
|
||||||
|
let conn = server.serve_connection(io, svc);
|
||||||
|
let fut = graceful.watch(conn);
|
||||||
|
tokio::spawn(async move {
|
||||||
|
// Errors are logged in the service_fn
|
||||||
|
let _ = fut.await;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
debug!("Shutting down discovery server");
|
_ = &mut close_rx => {
|
||||||
})
|
debug!("Shutting down discovery server");
|
||||||
.await;
|
break;
|
||||||
|
}
|
||||||
if let Err(e) = result {
|
}
|
||||||
warn!("Discovery server failed: {}", e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
graceful.shutdown().await;
|
||||||
|
debug!("Discovery server stopped");
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(Ok(Self {
|
Ok(Self {
|
||||||
cred_rx,
|
cred_rx,
|
||||||
_close_tx: close_tx,
|
_close_tx: close_tx,
|
||||||
}))
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue