mirror of
https://github.com/librespot-org/librespot.git
synced 2025-10-03 09:49:31 +02:00
Change panics into Result<_, librespot_core::Error>
This commit is contained in:
parent
a297c68913
commit
62461be1fc
69 changed files with 2041 additions and 1331 deletions
|
@ -1,49 +1,82 @@
|
|||
use std::env::consts::OS;
|
||||
|
||||
use bytes::Bytes;
|
||||
use futures_util::future::IntoStream;
|
||||
use futures_util::FutureExt;
|
||||
use futures_util::{future::IntoStream, FutureExt};
|
||||
use http::header::HeaderValue;
|
||||
use http::uri::InvalidUri;
|
||||
use hyper::client::{HttpConnector, ResponseFuture};
|
||||
use hyper::header::USER_AGENT;
|
||||
use hyper::{Body, Client, Request, Response, StatusCode};
|
||||
use hyper::{
|
||||
client::{HttpConnector, ResponseFuture},
|
||||
header::USER_AGENT,
|
||||
Body, Client, Request, Response, StatusCode,
|
||||
};
|
||||
use hyper_proxy::{Intercept, Proxy, ProxyConnector};
|
||||
use hyper_rustls::HttpsConnector;
|
||||
use rustls::{ClientConfig, RootCertStore};
|
||||
use thiserror::Error;
|
||||
use url::Url;
|
||||
|
||||
use std::env::consts::OS;
|
||||
|
||||
use crate::version::{
|
||||
FALLBACK_USER_AGENT, SPOTIFY_MOBILE_VERSION, SPOTIFY_VERSION, VERSION_STRING,
|
||||
use crate::{
|
||||
version::{FALLBACK_USER_AGENT, SPOTIFY_MOBILE_VERSION, SPOTIFY_VERSION, VERSION_STRING},
|
||||
Error,
|
||||
};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum HttpClientError {
|
||||
#[error("Response status code: {0}")]
|
||||
StatusCode(hyper::StatusCode),
|
||||
}
|
||||
|
||||
impl From<HttpClientError> for Error {
|
||||
fn from(err: HttpClientError) -> Self {
|
||||
match err {
|
||||
HttpClientError::StatusCode(code) => {
|
||||
// not exhaustive, but what reasonably could be expected
|
||||
match code {
|
||||
StatusCode::GATEWAY_TIMEOUT | StatusCode::REQUEST_TIMEOUT => {
|
||||
Error::deadline_exceeded(err)
|
||||
}
|
||||
StatusCode::GONE
|
||||
| StatusCode::NOT_FOUND
|
||||
| StatusCode::MOVED_PERMANENTLY
|
||||
| StatusCode::PERMANENT_REDIRECT
|
||||
| StatusCode::TEMPORARY_REDIRECT => Error::not_found(err),
|
||||
StatusCode::FORBIDDEN | StatusCode::PAYMENT_REQUIRED => {
|
||||
Error::permission_denied(err)
|
||||
}
|
||||
StatusCode::NETWORK_AUTHENTICATION_REQUIRED
|
||||
| StatusCode::PROXY_AUTHENTICATION_REQUIRED
|
||||
| StatusCode::UNAUTHORIZED => Error::unauthenticated(err),
|
||||
StatusCode::EXPECTATION_FAILED
|
||||
| StatusCode::PRECONDITION_FAILED
|
||||
| StatusCode::PRECONDITION_REQUIRED => Error::failed_precondition(err),
|
||||
StatusCode::RANGE_NOT_SATISFIABLE => Error::out_of_range(err),
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
| StatusCode::MISDIRECTED_REQUEST
|
||||
| StatusCode::SERVICE_UNAVAILABLE
|
||||
| StatusCode::UNAVAILABLE_FOR_LEGAL_REASONS => Error::unavailable(err),
|
||||
StatusCode::BAD_REQUEST
|
||||
| StatusCode::HTTP_VERSION_NOT_SUPPORTED
|
||||
| StatusCode::LENGTH_REQUIRED
|
||||
| StatusCode::METHOD_NOT_ALLOWED
|
||||
| StatusCode::NOT_ACCEPTABLE
|
||||
| StatusCode::PAYLOAD_TOO_LARGE
|
||||
| StatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE
|
||||
| StatusCode::UNSUPPORTED_MEDIA_TYPE
|
||||
| StatusCode::URI_TOO_LONG => Error::invalid_argument(err),
|
||||
StatusCode::TOO_MANY_REQUESTS => Error::resource_exhausted(err),
|
||||
StatusCode::NOT_IMPLEMENTED => Error::unimplemented(err),
|
||||
_ => Error::unknown(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct HttpClient {
|
||||
user_agent: HeaderValue,
|
||||
proxy: Option<Url>,
|
||||
tls_config: ClientConfig,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum HttpClientError {
|
||||
#[error("could not parse request: {0}")]
|
||||
Parsing(#[from] http::Error),
|
||||
#[error("could not send request: {0}")]
|
||||
Request(hyper::Error),
|
||||
#[error("could not read response: {0}")]
|
||||
Response(hyper::Error),
|
||||
#[error("status code: {0}")]
|
||||
NotOK(u16),
|
||||
#[error("could not build proxy connector: {0}")]
|
||||
ProxyBuilder(#[from] std::io::Error),
|
||||
}
|
||||
|
||||
impl From<InvalidUri> for HttpClientError {
|
||||
fn from(err: InvalidUri) -> Self {
|
||||
Self::Parsing(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl HttpClient {
|
||||
pub fn new(proxy: Option<&Url>) -> Self {
|
||||
let spotify_version = match OS {
|
||||
|
@ -53,7 +86,7 @@ impl HttpClient {
|
|||
|
||||
let spotify_platform = match OS {
|
||||
"android" => "Android/31",
|
||||
"ios" => "iOS/15.1.1",
|
||||
"ios" => "iOS/15.2",
|
||||
"macos" => "OSX/0",
|
||||
"windows" => "Win32/0",
|
||||
_ => "Linux/0",
|
||||
|
@ -95,37 +128,32 @@ impl HttpClient {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn request(&self, req: Request<Body>) -> Result<Response<Body>, HttpClientError> {
|
||||
pub async fn request(&self, req: Request<Body>) -> Result<Response<Body>, Error> {
|
||||
debug!("Requesting {:?}", req.uri().to_string());
|
||||
|
||||
let request = self.request_fut(req)?;
|
||||
{
|
||||
let response = request.await;
|
||||
if let Ok(response) = &response {
|
||||
let status = response.status();
|
||||
if status != StatusCode::OK {
|
||||
return Err(HttpClientError::NotOK(status.into()));
|
||||
}
|
||||
let response = request.await;
|
||||
|
||||
if let Ok(response) = &response {
|
||||
let code = response.status();
|
||||
if code != StatusCode::OK {
|
||||
return Err(HttpClientError::StatusCode(code).into());
|
||||
}
|
||||
response.map_err(HttpClientError::Response)
|
||||
}
|
||||
|
||||
Ok(response?)
|
||||
}
|
||||
|
||||
pub async fn request_body(&self, req: Request<Body>) -> Result<Bytes, HttpClientError> {
|
||||
pub async fn request_body(&self, req: Request<Body>) -> Result<Bytes, Error> {
|
||||
let response = self.request(req).await?;
|
||||
hyper::body::to_bytes(response.into_body())
|
||||
.await
|
||||
.map_err(HttpClientError::Response)
|
||||
Ok(hyper::body::to_bytes(response.into_body()).await?)
|
||||
}
|
||||
|
||||
pub fn request_stream(
|
||||
&self,
|
||||
req: Request<Body>,
|
||||
) -> Result<IntoStream<ResponseFuture>, HttpClientError> {
|
||||
pub fn request_stream(&self, req: Request<Body>) -> Result<IntoStream<ResponseFuture>, Error> {
|
||||
Ok(self.request_fut(req)?.into_stream())
|
||||
}
|
||||
|
||||
pub fn request_fut(&self, mut req: Request<Body>) -> Result<ResponseFuture, HttpClientError> {
|
||||
pub fn request_fut(&self, mut req: Request<Body>) -> Result<ResponseFuture, Error> {
|
||||
let mut http = HttpConnector::new();
|
||||
http.enforce_http(false);
|
||||
let connector = HttpsConnector::from((http, self.tls_config.clone()));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue