feature: add proxy config
This commit is contained in:
parent
e0a9115941
commit
5bf3909d46
14 changed files with 225 additions and 28 deletions
|
@ -26,6 +26,7 @@ nochanlists = []
|
||||||
json_config = ["serde", "serde_derive", "serde_json"]
|
json_config = ["serde", "serde_derive", "serde_json"]
|
||||||
toml_config = ["serde", "serde_derive", "toml"]
|
toml_config = ["serde", "serde_derive", "toml"]
|
||||||
yaml_config = ["serde", "serde_derive", "serde_yaml"]
|
yaml_config = ["serde", "serde_derive", "serde_yaml"]
|
||||||
|
proxy = ["tokio-socks"]
|
||||||
|
|
||||||
# Temporary transitionary features
|
# Temporary transitionary features
|
||||||
json = ["json_config"]
|
json = ["json_config"]
|
||||||
|
@ -44,6 +45,7 @@ serde = { version = "1.0", features = ["derive"], optional = true }
|
||||||
serde_derive = { version = "1.0", optional = true }
|
serde_derive = { version = "1.0", optional = true }
|
||||||
tokio = { version = "0.2.4", features = ["time", "net", "stream", "macros", "stream"] }
|
tokio = { version = "0.2.4", features = ["time", "net", "stream", "macros", "stream"] }
|
||||||
tokio-util = { version = "0.2.0", features = ["codec"] }
|
tokio-util = { version = "0.2.0", features = ["codec"] }
|
||||||
|
tokio-socks = { version = "0.2.0", optional = true }
|
||||||
tokio-tls = "0.3.0"
|
tokio-tls = "0.3.0"
|
||||||
serde_json = { version = "1.0", optional = true }
|
serde_json = { version = "1.0", optional = true }
|
||||||
serde_yaml = { version = "0.8", optional = true }
|
serde_yaml = { version = "0.8", optional = true }
|
||||||
|
@ -59,3 +61,8 @@ anyhow = "1.0.13"
|
||||||
args = "2.0"
|
args = "2.0"
|
||||||
getopts = "0.2"
|
getopts = "0.2"
|
||||||
env_logger = "0.7"
|
env_logger = "0.7"
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "proxy"
|
||||||
|
path = "examples/proxy.rs"
|
||||||
|
required-features = ["proxy"]
|
||||||
|
|
|
@ -104,6 +104,11 @@ realname = "Test User"
|
||||||
server = "chat.freenode.net"
|
server = "chat.freenode.net"
|
||||||
port = 6697
|
port = 6697
|
||||||
password = ""
|
password = ""
|
||||||
|
proxy_type = "None"
|
||||||
|
proxy_server = "127.0.0.1"
|
||||||
|
proxy_port = "1080"
|
||||||
|
proxy_username = ""
|
||||||
|
proxy_password = ""
|
||||||
use_ssl = true
|
use_ssl = true
|
||||||
cert_path = "cert.der"
|
cert_path = "cert.der"
|
||||||
client_cert_path = "client.der"
|
client_cert_path = "client.der"
|
||||||
|
|
|
@ -17,7 +17,6 @@ async fn main() -> irc::error::Result<()> {
|
||||||
nickname: Some("irc-crate-ci".to_owned()),
|
nickname: Some("irc-crate-ci".to_owned()),
|
||||||
server: Some("irc.pdgn.co".to_owned()),
|
server: Some("irc.pdgn.co".to_owned()),
|
||||||
alt_nicks: vec!["[irc-crate-ci]".to_owned()],
|
alt_nicks: vec!["[irc-crate-ci]".to_owned()],
|
||||||
use_ssl: true,
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
28
examples/proxy.rs
Normal file
28
examples/proxy.rs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
use futures::prelude::*;
|
||||||
|
use irc::client::data::ProxyType;
|
||||||
|
use irc::client::prelude::*;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> irc::error::Result<()> {
|
||||||
|
let config = Config {
|
||||||
|
nickname: Some("rust-irc-bot".to_owned()),
|
||||||
|
alt_nicks: vec!["bananas".to_owned(), "apples".to_owned()],
|
||||||
|
server: Some("irc.oftc.net".to_owned()),
|
||||||
|
channels: vec!["#rust-spam".to_owned()],
|
||||||
|
proxy_type: Some(ProxyType::Socks5),
|
||||||
|
proxy_server: Some("127.0.0.1".to_owned()),
|
||||||
|
proxy_port: Some(9050),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut client = Client::from_config(config).await?;
|
||||||
|
client.identify()?;
|
||||||
|
|
||||||
|
let mut stream = client.stream()?;
|
||||||
|
|
||||||
|
while let Some(message) = stream.next().await.transpose()? {
|
||||||
|
print!("{}", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -7,7 +7,6 @@ async fn main() -> irc::error::Result<()> {
|
||||||
nickname: Some("repeater".to_owned()),
|
nickname: Some("repeater".to_owned()),
|
||||||
alt_nicks: vec!["blaster".to_owned(), "smg".to_owned()],
|
alt_nicks: vec!["blaster".to_owned(), "smg".to_owned()],
|
||||||
server: Some("irc.mozilla.org".to_owned()),
|
server: Some("irc.mozilla.org".to_owned()),
|
||||||
use_ssl: true,
|
|
||||||
channels: vec!["#rust-spam".to_owned()],
|
channels: vec!["#rust-spam".to_owned()],
|
||||||
burst_window_length: Some(4),
|
burst_window_length: Some(4),
|
||||||
max_messages_in_burst: Some(4),
|
max_messages_in_burst: Some(4),
|
||||||
|
|
|
@ -7,7 +7,7 @@ async fn main() -> irc::error::Result<()> {
|
||||||
nickname: Some("pickles".to_owned()),
|
nickname: Some("pickles".to_owned()),
|
||||||
server: Some("irc.mozilla.org".to_owned()),
|
server: Some("irc.mozilla.org".to_owned()),
|
||||||
channels: vec!["#rust-spam".to_owned()],
|
channels: vec!["#rust-spam".to_owned()],
|
||||||
use_ssl: true,
|
use_ssl: Some(false),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,6 +13,12 @@ use tokio::net::TcpStream;
|
||||||
use tokio_tls::{self, TlsStream};
|
use tokio_tls::{self, TlsStream};
|
||||||
use tokio_util::codec::Decoder;
|
use tokio_util::codec::Decoder;
|
||||||
|
|
||||||
|
#[cfg(feature = "proxy")]
|
||||||
|
use tokio_socks::tcp::Socks5Stream;
|
||||||
|
|
||||||
|
#[cfg(feature = "proxy")]
|
||||||
|
use crate::client::data::ProxyType;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
client::{
|
client::{
|
||||||
data::Config,
|
data::Config,
|
||||||
|
@ -76,8 +82,8 @@ impl Connection {
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.use_ssl() {
|
if config.use_ssl() {
|
||||||
let domain = format!("{}", config.server()?);
|
log::info!("Building SSL connection.");
|
||||||
log::info!("Connecting via SSL to {}.", domain);
|
|
||||||
let mut builder = TlsConnector::builder();
|
let mut builder = TlsConnector::builder();
|
||||||
|
|
||||||
if let Some(cert_path) = config.cert_path() {
|
if let Some(cert_path) = config.cert_path() {
|
||||||
|
@ -103,15 +109,14 @@ impl Connection {
|
||||||
}
|
}
|
||||||
let connector: tokio_tls::TlsConnector = builder.build()?.into();
|
let connector: tokio_tls::TlsConnector = builder.build()?.into();
|
||||||
|
|
||||||
let socket = TcpStream::connect(config.to_socket_addrs()?).await?;
|
let socket = Self::new_conn(config).await?;
|
||||||
let stream = connector.connect(&domain, socket).await?;
|
let stream = connector.connect(config.server()?, socket).await?;
|
||||||
let framed = IrcCodec::new(config.encoding())?.framed(stream);
|
let framed = IrcCodec::new(config.encoding())?.framed(stream);
|
||||||
let transport = Transport::new(&config, framed, tx);
|
let transport = Transport::new(&config, framed, tx);
|
||||||
|
|
||||||
Ok(Connection::Secured(transport))
|
Ok(Connection::Secured(transport))
|
||||||
} else {
|
} else {
|
||||||
log::info!("Connecting to {}.", config.server()?);
|
let stream = Self::new_conn(config).await?;
|
||||||
let stream = TcpStream::connect(config.to_socket_addrs()?).await?;
|
|
||||||
let framed = IrcCodec::new(config.encoding())?.framed(stream);
|
let framed = IrcCodec::new(config.encoding())?.framed(stream);
|
||||||
let transport = Transport::new(&config, framed, tx);
|
let transport = Transport::new(&config, framed, tx);
|
||||||
|
|
||||||
|
@ -119,6 +124,60 @@ impl Connection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "proxy"))]
|
||||||
|
async fn new_conn(config: &Config) -> error::Result<TcpStream> {
|
||||||
|
let server = config.server()?;
|
||||||
|
let port = config.port();
|
||||||
|
let address = (server, port);
|
||||||
|
|
||||||
|
log::info!(
|
||||||
|
"Connecting to {:?} using SSL: {}",
|
||||||
|
address,
|
||||||
|
config.use_ssl()
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(TcpStream::connect(address).await?)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "proxy")]
|
||||||
|
async fn new_conn(config: &Config) -> error::Result<TcpStream> {
|
||||||
|
let server = config.server()?;
|
||||||
|
let port = config.port();
|
||||||
|
let address = (server, port);
|
||||||
|
|
||||||
|
log::info!(
|
||||||
|
"Connecting to {:?} using SSL: {}",
|
||||||
|
address,
|
||||||
|
config.use_ssl()
|
||||||
|
);
|
||||||
|
|
||||||
|
match config.proxy_type() {
|
||||||
|
ProxyType::None => Ok(TcpStream::connect(address).await?),
|
||||||
|
_ => {
|
||||||
|
let proxy_server = config.proxy_server();
|
||||||
|
let proxy_port = config.proxy_port();
|
||||||
|
let proxy_username = config.proxy_username();
|
||||||
|
let proxy_password = config.proxy_password();
|
||||||
|
let proxy = (proxy_server, proxy_port);
|
||||||
|
|
||||||
|
log::info!("Setup proxy {:?}.", proxy);
|
||||||
|
|
||||||
|
if !proxy_username.is_empty() || !proxy_password.is_empty() {
|
||||||
|
return Ok(Socks5Stream::connect_with_password(
|
||||||
|
proxy,
|
||||||
|
address,
|
||||||
|
proxy_username,
|
||||||
|
proxy_password,
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
.into_inner());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Socks5Stream::connect(proxy, address).await?.into_inner())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Gets a view of the internal logging if and only if this connection is using a mock stream.
|
/// Gets a view of the internal logging if and only if this connection is using a mock stream.
|
||||||
/// Otherwise, this will always return `None`. This is used for unit testing.
|
/// Otherwise, this will always return `None`. This is used for unit testing.
|
||||||
pub fn log_view(&self) -> Option<LogView> {
|
pub fn log_view(&self) -> Option<LogView> {
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
"password": "",
|
"password": "",
|
||||||
"server": "irc.test.net",
|
"server": "irc.test.net",
|
||||||
"port": 6667,
|
"port": 6667,
|
||||||
"use_ssl": false,
|
|
||||||
"encoding": "UTF-8",
|
"encoding": "UTF-8",
|
||||||
"channels": [
|
"channels": [
|
||||||
"#test",
|
"#test",
|
||||||
|
|
|
@ -5,7 +5,6 @@ realname = "test"
|
||||||
server = "irc.test.net"
|
server = "irc.test.net"
|
||||||
port = 6667
|
port = 6667
|
||||||
password = ""
|
password = ""
|
||||||
use_ssl = false
|
|
||||||
encoding = "UTF-8"
|
encoding = "UTF-8"
|
||||||
channels = ["#test", "#test2"]
|
channels = ["#test", "#test2"]
|
||||||
umodes = "+BR"
|
umodes = "+BR"
|
||||||
|
|
|
@ -7,7 +7,6 @@ realname: test
|
||||||
server: irc.test.net
|
server: irc.test.net
|
||||||
port: 6667
|
port: 6667
|
||||||
password: ""
|
password: ""
|
||||||
use_ssl: false
|
|
||||||
encoding: UTF-8
|
encoding: UTF-8
|
||||||
channels:
|
channels:
|
||||||
- "#test"
|
- "#test"
|
||||||
|
|
|
@ -7,7 +7,6 @@ use std::{
|
||||||
io::prelude::*,
|
io::prelude::*,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
use tokio::net::ToSocketAddrs;
|
|
||||||
|
|
||||||
#[cfg(feature = "json_config")]
|
#[cfg(feature = "json_config")]
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
@ -16,6 +15,9 @@ use serde_yaml;
|
||||||
#[cfg(feature = "toml_config")]
|
#[cfg(feature = "toml_config")]
|
||||||
use toml;
|
use toml;
|
||||||
|
|
||||||
|
#[cfg(feature = "proxy")]
|
||||||
|
use crate::client::data::proxy::ProxyType;
|
||||||
|
|
||||||
use crate::error::Error::InvalidConfig;
|
use crate::error::Error::InvalidConfig;
|
||||||
#[cfg(feature = "toml_config")]
|
#[cfg(feature = "toml_config")]
|
||||||
use crate::error::TomlError;
|
use crate::error::TomlError;
|
||||||
|
@ -98,11 +100,30 @@ pub struct Config {
|
||||||
/// The password to connect to the server.
|
/// The password to connect to the server.
|
||||||
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
pub password: Option<String>,
|
pub password: Option<String>,
|
||||||
|
/// The proxy type to connect to.
|
||||||
|
#[cfg(feature = "proxy")]
|
||||||
|
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
|
pub proxy_type: Option<ProxyType>,
|
||||||
|
/// The proxy server to connect to.
|
||||||
|
#[cfg(feature = "proxy")]
|
||||||
|
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
|
pub proxy_server: Option<String>,
|
||||||
|
/// The proxy port to connect on.
|
||||||
|
#[cfg(feature = "proxy")]
|
||||||
|
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
|
pub proxy_port: Option<u16>,
|
||||||
|
/// The username to connect to the proxy server.
|
||||||
|
#[cfg(feature = "proxy")]
|
||||||
|
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
|
pub proxy_username: Option<String>,
|
||||||
|
/// The password to connect to the proxy server.
|
||||||
|
#[cfg(feature = "proxy")]
|
||||||
|
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
|
pub proxy_password: Option<String>,
|
||||||
/// Whether or not to use SSL.
|
/// Whether or not to use SSL.
|
||||||
/// Clients will automatically panic if this is enabled without SSL support.
|
/// Clients will automatically panic if this is enabled without SSL support.
|
||||||
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "is_false"))]
|
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
#[cfg_attr(feature = "serde", serde(default))]
|
pub use_ssl: Option<bool>,
|
||||||
pub use_ssl: bool,
|
|
||||||
/// The path to the SSL certificate for this server in DER format.
|
/// The path to the SSL certificate for this server in DER format.
|
||||||
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
pub cert_path: Option<String>,
|
pub cert_path: Option<String>,
|
||||||
|
@ -415,31 +436,64 @@ impl Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the port of the server specified in the configuration.
|
/// Gets the port of the server specified in the configuration.
|
||||||
/// This defaults to 6667 (or 6697 if use_ssl is specified as true) when not specified.
|
/// This defaults to 6697 (or 6667 if use_ssl is specified as false) when not specified.
|
||||||
pub fn port(&self) -> u16 {
|
pub fn port(&self) -> u16 {
|
||||||
self.port
|
self.port
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.cloned()
|
.cloned()
|
||||||
.unwrap_or(if self.use_ssl() { 6697 } else { 6667 })
|
.unwrap_or(match self.use_ssl() {
|
||||||
}
|
true => 6697,
|
||||||
|
false => 6667
|
||||||
/// Return something that can be converted into a socket address by tokio.
|
})
|
||||||
pub(crate) fn to_socket_addrs(&self) -> Result<impl ToSocketAddrs + '_> {
|
|
||||||
let server = self.server()?;
|
|
||||||
let port = self.port();
|
|
||||||
Ok((server, port))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the server password specified in the configuration.
|
/// Gets the server password specified in the configuration.
|
||||||
/// This defaults to a blank string when not specified.
|
/// This defaults to an empty string when not specified.
|
||||||
pub fn password(&self) -> &str {
|
pub fn password(&self) -> &str {
|
||||||
self.password.as_ref().map_or("", String::as_str)
|
self.password.as_ref().map_or("", String::as_str)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the type of the proxy specified in the configuration.
|
||||||
|
/// This defaults to a None ProxyType when not specified.
|
||||||
|
#[cfg(feature = "proxy")]
|
||||||
|
pub fn proxy_type(&self) -> ProxyType {
|
||||||
|
self.proxy_type.as_ref().cloned().unwrap_or(ProxyType::None)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the address of the proxy specified in the configuration.
|
||||||
|
/// This defaults to "localhost" string when not specified.
|
||||||
|
#[cfg(feature = "proxy")]
|
||||||
|
pub fn proxy_server(&self) -> &str {
|
||||||
|
self.proxy_server
|
||||||
|
.as_ref()
|
||||||
|
.map_or("localhost", String::as_str)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the port of the proxy specified in the configuration.
|
||||||
|
/// This defaults to 1080 when not specified.
|
||||||
|
#[cfg(feature = "proxy")]
|
||||||
|
pub fn proxy_port(&self) -> u16 {
|
||||||
|
self.proxy_port.as_ref().cloned().unwrap_or(1080)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the username of the proxy specified in the configuration.
|
||||||
|
/// This defaults to an empty string when not specified.
|
||||||
|
#[cfg(feature = "proxy")]
|
||||||
|
pub fn proxy_username(&self) -> &str {
|
||||||
|
self.proxy_username.as_ref().map_or("", String::as_str)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the password of the proxy specified in the configuration.
|
||||||
|
/// This defaults to an empty string when not specified.
|
||||||
|
#[cfg(feature = "proxy")]
|
||||||
|
pub fn proxy_password(&self) -> &str {
|
||||||
|
self.proxy_password.as_ref().map_or("", String::as_str)
|
||||||
|
}
|
||||||
|
|
||||||
/// Gets whether or not to use SSL with this connection.
|
/// Gets whether or not to use SSL with this connection.
|
||||||
/// This defaults to false when not specified.
|
/// This defaults to true when not specified.
|
||||||
pub fn use_ssl(&self) -> bool {
|
pub fn use_ssl(&self) -> bool {
|
||||||
self.use_ssl
|
self.use_ssl.as_ref().cloned().map_or(true, |s| s)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the path to the SSL certificate in DER format if specified.
|
/// Gets the path to the SSL certificate in DER format if specified.
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
//! Data related to IRC functionality.
|
//! Data related to IRC functionality.
|
||||||
|
|
||||||
pub use crate::client::data::config::Config;
|
pub use crate::client::data::config::Config;
|
||||||
|
#[cfg(feature = "proxy")]
|
||||||
|
pub use crate::client::data::proxy::ProxyType;
|
||||||
pub use crate::client::data::user::{AccessLevel, User};
|
pub use crate::client::data::user::{AccessLevel, User};
|
||||||
|
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
#[cfg(feature = "proxy")]
|
||||||
|
pub mod proxy;
|
||||||
pub mod user;
|
pub mod user;
|
||||||
|
|
33
src/client/data/proxy.rs
Normal file
33
src/client/data/proxy.rs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
//! A feature which allow us to connect to IRC via a proxy.
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! use irc::client::prelude::Config;
|
||||||
|
//! use irc::client::data::ProxyType;
|
||||||
|
//!
|
||||||
|
//! # fn main() {
|
||||||
|
//! let config = Config {
|
||||||
|
//! nickname: Some("test".to_owned()),
|
||||||
|
//! server: Some("irc.example.com".to_owned()),
|
||||||
|
//! proxy_type: Some(ProxyType::Socks5),
|
||||||
|
//! proxy_server: Some("127.0.0.1".to_owned()),
|
||||||
|
//! proxy_port: Some(9050),
|
||||||
|
//! ..Config::default()
|
||||||
|
//! };
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// An enum which defines which type of proxy should be in use.
|
||||||
|
#[cfg(feature = "proxy")]
|
||||||
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
pub enum ProxyType {
|
||||||
|
/// Does not use any proxy.
|
||||||
|
None,
|
||||||
|
|
||||||
|
/// Use a SOCKS5 proxy.
|
||||||
|
/// DNS queries are also sent via the proxy.
|
||||||
|
Socks5,
|
||||||
|
}
|
12
src/error.rs
12
src/error.rs
|
@ -21,6 +21,11 @@ pub enum Error {
|
||||||
#[error("an io error occurred")]
|
#[error("an io error occurred")]
|
||||||
Io(#[source] IoError),
|
Io(#[source] IoError),
|
||||||
|
|
||||||
|
/// An internal proxy error.
|
||||||
|
#[cfg(feature = "proxy")]
|
||||||
|
#[error("a proxy error occurred")]
|
||||||
|
Proxy(tokio_socks::Error),
|
||||||
|
|
||||||
/// An internal TLS error.
|
/// An internal TLS error.
|
||||||
#[error("a TLS error occurred")]
|
#[error("a TLS error occurred")]
|
||||||
Tls(#[source] native_tls::Error),
|
Tls(#[source] native_tls::Error),
|
||||||
|
@ -164,6 +169,13 @@ impl From<IoError> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "proxy")]
|
||||||
|
impl From<tokio_socks::Error> for Error {
|
||||||
|
fn from(e: tokio_socks::Error) -> Error {
|
||||||
|
Error::Proxy(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<native_tls::Error> for Error {
|
impl From<native_tls::Error> for Error {
|
||||||
fn from(e: native_tls::Error) -> Error {
|
fn from(e: native_tls::Error) -> Error {
|
||||||
Error::Tls(e)
|
Error::Tls(e)
|
||||||
|
|
Loading…
Add table
Reference in a new issue