Replace error_chain by thiserror

This commit is contained in:
johannesd3 2021-02-13 11:53:23 +01:00 committed by Johannesd3
parent 45f42acb82
commit 27f308b82f
6 changed files with 63 additions and 55 deletions

2
Cargo.lock generated
View file

@ -1435,7 +1435,6 @@ dependencies = [
"bytes", "bytes",
"cfg-if 1.0.0", "cfg-if 1.0.0",
"env_logger", "env_logger",
"error-chain",
"futures-core", "futures-core",
"futures-sink", "futures-sink",
"futures-util", "futures-util",
@ -1455,6 +1454,7 @@ dependencies = [
"serde_json", "serde_json",
"sha-1 0.9.4", "sha-1 0.9.4",
"shannon", "shannon",
"thiserror",
"tokio", "tokio",
"tokio-stream", "tokio-stream",
"tokio-util", "tokio-util",

View file

@ -18,7 +18,6 @@ base64 = "0.13"
byteorder = "1.4" byteorder = "1.4"
bytes = "1.0" bytes = "1.0"
cfg-if = "1" cfg-if = "1"
error-chain = { version = "0.12", default-features = false }
futures-core = { version = "0.3", default-features = false } futures-core = { version = "0.3", default-features = false }
futures-sink = { 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"] } 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" serde_json = "1.0"
sha-1 = "0.9" sha-1 = "0.9"
shannon = "0.2.0" shannon = "0.2.0"
thiserror = "1"
tokio = { version = "1.0", features = ["io-util", "net", "rt", "sync"] } tokio = { version = "1.0", features = ["io-util", "net", "rt", "sync"] }
tokio-stream = "0.1" tokio-stream = "0.1"
tokio-util = { version = "0.6", features = ["codec"] } tokio-util = { version = "0.6", features = ["codec"] }

View file

@ -1,5 +1,4 @@
use std::io::{self, Read}; use std::io::{self, Read};
use std::ops::FnOnce;
use aes::Aes192; use aes::Aes192;
use byteorder::{BigEndian, ByteOrder}; use byteorder::{BigEndian, ByteOrder};
@ -10,7 +9,6 @@ use serde::{Deserialize, Serialize};
use sha1::{Digest, Sha1}; use sha1::{Digest, Sha1};
use crate::protocol::authentication::AuthenticationType; use crate::protocol::authentication::AuthenticationType;
use crate::protocol::keyexchange::{APLoginFailed, ErrorCode};
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Credentials { pub struct Credentials {
@ -144,37 +142,3 @@ where
let v: String = serde::Deserialize::deserialize(de)?; let v: String = serde::Deserialize::deserialize(de)?;
base64::decode(&v).map_err(|e| serde::de::Error::custom(e.to_string())) 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<APLoginFailed> 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(),
}
}
}

View file

@ -4,21 +4,60 @@ mod handshake;
pub use self::codec::APCodec; pub use self::codec::APCodec;
pub use self::handshake::handshake; pub use self::handshake::handshake;
use futures_util::{SinkExt, StreamExt}; use std::io::{self, ErrorKind};
use protobuf::{self, Message};
use std::io;
use std::net::ToSocketAddrs; use std::net::ToSocketAddrs;
use futures_util::{SinkExt, StreamExt};
use protobuf::{self, Message, ProtobufError};
use thiserror::Error;
use tokio::net::TcpStream; use tokio::net::TcpStream;
use tokio_util::codec::Framed; use tokio_util::codec::Framed;
use url::Url; use url::Url;
use crate::authentication::{AuthenticationError, Credentials}; use crate::authentication::Credentials;
use crate::protocol::keyexchange::{APLoginFailed, ErrorCode};
use crate::proxytunnel;
use crate::version; use crate::version;
use crate::proxytunnel;
pub type Transport = Framed<TcpStream, APCodec>; pub type Transport = Framed<TcpStream, APCodec>;
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<ProtobufError> for AuthenticationError {
fn from(e: ProtobufError) -> Self {
io::Error::new(ErrorKind::InvalidData, e).into()
}
}
impl From<APLoginFailed> for AuthenticationError {
fn from(login_failure: APLoginFailed) -> Self {
Self::LoginFailed(login_failure.get_error_code())
}
}
pub async fn connect(addr: String, proxy: &Option<Url>) -> io::Result<Transport> { pub async fn connect(addr: String, proxy: &Option<Url>) -> io::Result<Transport> {
let socket = if let Some(proxy) = proxy { let socket = if let Some(proxy) = proxy {
info!("Using proxy \"{}\"", proxy); info!("Using proxy \"{}\"", proxy);
@ -66,7 +105,6 @@ pub async fn authenticate(
device_id: &str, device_id: &str,
) -> Result<Credentials, AuthenticationError> { ) -> Result<Credentials, AuthenticationError> {
use crate::protocol::authentication::{APWelcome, ClientResponseEncrypted, CpuFamily, Os}; use crate::protocol::authentication::{APWelcome, ClientResponseEncrypted, CpuFamily, Os};
use crate::protocol::keyexchange::APLoginFailed;
let mut packet = ClientResponseEncrypted::new(); let mut packet = ClientResponseEncrypted::new();
packet packet
@ -101,7 +139,7 @@ pub async fn authenticate(
let (cmd, data) = transport.next().await.expect("EOF")?; let (cmd, data) = transport.next().await.expect("EOF")?;
match cmd { match cmd {
0xac => { 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 { let reusable_credentials = Credentials {
username: welcome_data.get_canonical_username().to_owned(), username: welcome_data.get_canonical_username().to_owned(),
@ -111,12 +149,13 @@ pub async fn authenticate(
Ok(reusable_credentials) Ok(reusable_credentials)
} }
0xad => { 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()) Err(error_data.into())
} }
_ => {
_ => panic!("Unexpected packet {:?}", cmd), let msg = format!("Received invalid packet: {}", cmd);
Err(io::Error::new(ErrorKind::InvalidData, msg).into())
}
} }
} }

View file

@ -4,8 +4,6 @@
extern crate log; extern crate log;
#[macro_use] #[macro_use]
extern crate cfg_if; extern crate cfg_if;
#[macro_use]
extern crate error_chain;
use librespot_protocol as protocol; use librespot_protocol as protocol;

View file

@ -12,6 +12,7 @@ use bytes::Bytes;
use futures_core::TryStream; use futures_core::TryStream;
use futures_util::{FutureExt, StreamExt, TryStreamExt}; use futures_util::{FutureExt, StreamExt, TryStreamExt};
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use thiserror::Error;
use tokio::sync::mpsc; use tokio::sync::mpsc;
use tokio_stream::wrappers::UnboundedReceiverStream; use tokio_stream::wrappers::UnboundedReceiverStream;
@ -21,10 +22,16 @@ use crate::authentication::Credentials;
use crate::cache::Cache; use crate::cache::Cache;
use crate::channel::ChannelManager; use crate::channel::ChannelManager;
use crate::config::SessionConfig; use crate::config::SessionConfig;
use crate::connection; use crate::connection::{self, AuthenticationError};
use crate::mercury::MercuryManager; 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 { struct SessionData {
country: String, country: String,
@ -59,7 +66,7 @@ impl Session {
config: SessionConfig, config: SessionConfig,
credentials: Credentials, credentials: Credentials,
cache: Option<Cache>, cache: Option<Cache>,
) -> Result<Session, AuthenticationError> { ) -> Result<Session, SessionError> {
let ap = apresolve_or_fallback(&config.proxy, &config.ap_port).await; let ap = apresolve_or_fallback(&config.proxy, &config.ap_port).await;
info!("Connecting to AP \"{}\"", ap); info!("Connecting to AP \"{}\"", ap);