Skip to content

Commit

Permalink
33 bug features are not additive (#34)
Browse files Browse the repository at this point in the history
* sync with multi type

* async with additive features

* My boss forced me to build this feature... Pure shit.

* release notes
  • Loading branch information
veeso committed Feb 24, 2023
1 parent 9946de5 commit 7b252ed
Show file tree
Hide file tree
Showing 18 changed files with 681 additions and 280 deletions.
24 changes: 6 additions & 18 deletions .github/workflows/cargo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,31 +42,19 @@ jobs:
with:
command: build
args: --features async-native-tls,deprecated --package suppaftp
- name: Run tests (native-tls)
- name: Build all features
uses: actions-rs/cargo@v1
with:
command: test
args: --lib --package suppaftp --no-default-features --features native-tls,async-native-tls,with-containers --no-fail-fast
env:
RUST_LOG: trace
- name: Run tests (rustls)
command: build
args: --features deprecated,native-tls,rustls,async-native-tls,async-rustls --package suppaftp
- name: Run tests
uses: actions-rs/cargo@v1
with:
command: test
args: --lib --package suppaftp --no-default-features --features rustls,async-rustls,with-containers --no-fail-fast
args: --lib --package suppaftp --no-default-features --features rustls,native-tls,async-native-tls,async-rustls,with-containers --no-fail-fast
env:
RUST_LOG: trace
- name: Format
run: cargo fmt --all -- --check
- name: Clippy
run: cargo clippy --package suppaftp --features deprecated -- -Dwarnings
- name: Clippy (async)
run: cargo clippy --package suppaftp --features async,deprecated -- -Dwarnings
- name: Clippy (native-tls)
run: cargo clippy --package suppaftp --features native-tls,deprecated -- -Dwarnings
- name: Clippy (async-native-tls)
run: cargo clippy --package suppaftp --features async-native-tls,deprecated -- -Dwarnings
- name: Clippy (rustls)
run: cargo clippy --package suppaftp --features rustls,deprecated -- -Dwarnings
- name: Clippy (async-rustls)
run: cargo clippy --package suppaftp --features async-rustls,deprecated -- -Dwarnings
run: cargo clippy --package suppaftp --features deprecated,native-tls,rustls,async-native-tls,async-rustls -- -Dwarnings
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Changelog

- [Changelog](#changelog)
- [5.0.0](#500)
- [4.7.0](#470)
- [4.6.1](#461)
- [4.6.0](#460)
Expand All @@ -21,6 +22,20 @@

---

## 5.0.0

Released on 24/02/2023

- [Issue 33](https://github.com/veeso/suppaftp/issues/33) **‼️ BREAKING CHANGES ‼️**
- Features are now additive. This means that you can successfully build suppaftp with all the features enabled at the same time.
- Ftp stream has now been split into different types:
- `FtpStream`: sync no-tls stream
- `NativeTlsFtpStream`: ftp stream with TLS with native-tls
- `RustlsFtpStream`: ftp stream with TLS with rustls
- `AsyncFtpStream`: async no-tls stream
- `AsyncNativeTlsFtpStream`: async ftp stream with TLS with async-native-tls
- `AsyncRustlsFtpStream`: async ftp stream with TLS with async-rustls

## 4.7.0

Released on 01/02/2023
Expand Down
47 changes: 22 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</p>

<p align="center">Developed by <a href="https://veeso.github.io/">veeso</a> and <a href="https://github.com/mattnenterprise">Matt McCoy</a></p>
<p align="center">Current version: 4.7.0 (01/02/2023)</p>
<p align="center">Current version: 5.0.0 (24/02/2023)</p>

<p align="center">
<a href="https://opensource.org/licenses/MIT"
Expand Down Expand Up @@ -116,7 +116,7 @@ SuppaFTP is the main FTP/FTPS client library for Rust, with both support for syn
To get started, first add **suppaftp** to your dependencies:

```toml
suppaftp = "^4.7.0"
suppaftp = "^5.0.0"
```

### Features
Expand All @@ -126,24 +126,24 @@ suppaftp = "^4.7.0"
If you want to enable **support for FTPS**, you must enable the `native-tls` or `rustls` feature in your cargo dependencies, based on the TLS provider you prefer.

```toml
suppaftp = { version = "^4.7.0", features = ["native-tls"] }
suppaftp = { version = "^5.0.0", features = ["native-tls"] }
# or
suppaftp = { version = "^4.7.0", features = ["rustls"] }
suppaftp = { version = "^5.0.0", features = ["rustls"] }
```

> 💡 If you don't know what to choose, `native-tls` should be preferred for compatibility reasons.
> 💡 If you don't know what to choose, `native-tls` should be preferred for compatibility reasons.
> ❗ If you want to link libssl statically, enable feature `native-tls-vendored`
#### Async support

If you want to enable **async** support, you must enable `async` feature in your cargo dependencies.

```toml
suppaftp = { version = "^4.7.0", features = ["async"] }
suppaftp = { version = "^5.0.0", features = ["async"] }
```

> ⚠️ If you want to enable both **native-tls** and **async** you must use the **async-native-tls** feature ⚠️
> ⚠️ If you want to enable both **rustls** and **async** you must use the **async-rustls** feature ⚠️
> ⚠️ If you want to enable both **native-tls** and **async** you must use the **async-native-tls** feature ⚠️
> ⚠️ If you want to enable both **rustls** and **async** you must use the **async-rustls** feature ⚠️
> ❗ If you want to link libssl statically, enable feature `async-native-tls-vendored`
#### Deprecated methods
Expand Down Expand Up @@ -194,18 +194,16 @@ fn main() {
#### Ftp with TLS (native-tls)

```rust
use std::str;
use std::io::Cursor;
use suppaftp::{FtpStream};
use suppaftp::native_tls::TlsConnector;
use suppaftp::{NativeTlsFtpStream, NativeTlsConnector};
use suppaftp::native_tls::{TlsConnector, TlsStream};

fn main() {
// Create a connection to an FTP server and authenticate to it.
let mut ftp_stream = FtpStream::connect("127.0.0.1:21")
.into_secure(NativeTlsConnector::new().unwrap().into(), "domain-name")
.unwrap();
// Terminate the connection to the server.
let _ = ftp_stream.quit();
let ftp_stream = NativeTlsFtpStream::connect("test.rebex.net:21").unwrap();
// Switch to the secure mode
let mut ftp_stream = ftp_stream.into_secure(NativeTlsConnector::from(TlsConnector::new().unwrap()), "test.rebex.net").unwrap();
ftp_stream.login("demo", "password").unwrap();
// Do other secret stuff
assert!(ftp_stream.quit().is_ok());
}
```

Expand All @@ -215,7 +213,7 @@ fn main() {
use std::str;
use std::io::Cursor;
use std::sync::Arc;
use suppaftp::{FtpStream};
use suppaftp::{RustlsFtpStream, RustlsConnector};
use suppaftp::rustls::ClientConfig;

fn main() {
Expand All @@ -233,9 +231,9 @@ fn main() {
.with_no_client_auth();
// Create a connection to an FTP server and authenticate to it.
let config = Arc::new(rustls_config());
let mut ftp_stream = FtpStream::connect("test.rebex.net:21")
let mut ftp_stream = RustlsFtpStream::connect("test.rebex.net:21")
.unwrap()
.into_secure(Arc::clone(&config).into(), "test.rebex.net")
.into_secure(RustlsConnector::from(Arc::clone(&config)), "test.rebex.net")
.unwrap();
// Terminate the connection to the server.
let _ = ftp_stream.quit();
Expand All @@ -245,14 +243,13 @@ fn main() {
#### Going Async

```rust
use suppaftp::FtpStream;
use suppaftp::{AsyncFtpStream, AsyncNativeTlsConnector};
use suppaftp::async_native_tls::{TlsConnector, TlsStream};
let ftp_stream = FtpStream::connect("test.rebex.net:21").await.unwrap();
let ftp_stream = AsyncFtpStream::connect("test.rebex.net:21").await.unwrap();
// Switch to the secure mode
let mut ftp_stream = ftp_stream.into_secure(TlsConnector::new().into(), "test.rebex.net").await.unwrap();
let mut ftp_stream = ftp_stream.into_secure(AsyncNativeTlsConnector::from(TlsConnector::new()), "test.rebex.net").await.unwrap();
ftp_stream.login("demo", "password").await.unwrap();
// Do other secret stuff
// Do all public stuff
assert!(ftp_stream.quit().await.is_ok());
```

Expand Down
4 changes: 2 additions & 2 deletions suppaftp-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ license = "MIT"
name = "suppaftp-cli"
readme = "../README.md"
repository = "https://github.com/veeso/suppaftp"
version = "4.7.0"
version = "5.0.0"

[[bin]]
name = "suppaftp"
Expand All @@ -21,4 +21,4 @@ argh = "^0.1"
env_logger = "^0.10"
log = "^0.4"
rpassword = "^7.2"
suppaftp = { path = "../suppaftp", version = "^4.7", features = [ "native-tls" ] }
suppaftp = { path = "../suppaftp", version = "^5.0", features = [ "native-tls" ] }
4 changes: 2 additions & 2 deletions suppaftp-cli/src/actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::io;
use std::path::Path;
use suppaftp::native_tls::TlsConnector;
use suppaftp::types::FileType;
use suppaftp::Mode;
use suppaftp::{Mode, NativeTlsConnector};

pub fn quit(mut ftp: Option<FtpStream>) {
if let Some(mut ftp) = ftp.take() {
Expand Down Expand Up @@ -60,7 +60,7 @@ pub fn connect(remote: &str, secure: bool) -> Option<FtpStream> {
};
// Get address without port
let address: &str = remote.split(':').next().unwrap();
stream = match stream.into_secure(ctx.into(), address) {
stream = match stream.into_secure(NativeTlsConnector::from(ctx), address) {
Ok(s) => s,
Err(err) => {
eprintln!("Failed to setup TLS stream: {err}");
Expand Down
2 changes: 1 addition & 1 deletion suppaftp-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use log::LevelFilter;
use std::io;
use std::io::Write;
use std::str::FromStr;
use suppaftp::{FtpError, FtpStream};
use suppaftp::{FtpError, NativeTlsFtpStream as FtpStream};

const APP_VERSION: &str = env!("CARGO_PKG_VERSION");
const APP_AUTHORS: &str = env!("CARGO_PKG_AUTHORS");
Expand Down
5 changes: 3 additions & 2 deletions suppaftp/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "suppaftp"
version = "4.7.0"
version = "5.0.0"
authors = ["Christian Visintin <christian.visintin1997@gmail.com>", "Matt McCoy <mattnenterprise@yahoo.com>"]
edition = "2021"
documentation = "https://docs.rs/suppaftp/"
Expand All @@ -24,6 +24,7 @@ thiserror = "^1"
# async
async-std = { version = "^1.10", optional = true }
async-native-tls-crate = { package = "async-native-tls", version = "^0.4", optional = true }
async-trait = { version = "0.1.64", optional = true }
async-tls = { version = "^0.11", optional = true }
pin-project = { version = "^1", optional = true }
# secure
Expand All @@ -41,7 +42,7 @@ webpki-roots = "0.22.5"
[features]
default = [ ]
# Enable async support for suppaftp
async = ["async-std", "pin-project"]
async = ["async-std", "async-trait", "pin-project"]
async-default-tls = [ "async-native-tls" ]
async-native-tls = [ "async-native-tls-crate", "async-secure" ]
async-rustls = [ "async-tls", "async-secure" ]
Expand Down
39 changes: 23 additions & 16 deletions suppaftp/src/async_ftp/data_stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,30 @@
//!
//! This module exposes the async data stream implementation where bytes must be written to/read from

#[cfg(feature = "async-native-tls")]
use async_native_tls::TlsStream;
#[cfg(any(feature = "async", feature = "async-secure"))]
use async_std::io::{Read, Result, Write};
#[cfg(any(feature = "async", feature = "async-secure"))]
use async_std::net::TcpStream;
#[cfg(feature = "async-rustls")]
use async_tls::client::TlsStream;
use pin_project::pin_project;
use std::pin::Pin;

use super::AsyncTlsStream;

/// Data Stream used for communications. It can be both of type Tcp in case of plain communication or Ssl in case of FTPS
#[pin_project(project = DataStreamProj)]
pub enum DataStream {
pub enum DataStream<T>
where
T: AsyncTlsStream,
{
Tcp(#[pin] TcpStream),
#[cfg(feature = "async-secure")]
Ssl(#[pin] Box<TlsStream<TcpStream>>),
Ssl(#[pin] Box<T>),
}

#[cfg(feature = "async-secure")]
impl DataStream {
impl<T> DataStream<T>
where
T: AsyncTlsStream,
{
/// Unwrap the stream into TcpStream. This method is only used in secure connection.
pub fn into_tcp_stream(self) -> TcpStream {
match self {
Expand All @@ -32,42 +35,48 @@ impl DataStream {
}
}

impl DataStream {
impl<T> DataStream<T>
where
T: AsyncTlsStream,
{
/// Returns a reference to the underlying TcpStream.
pub fn get_ref(&self) -> &TcpStream {
match self {
DataStream::Tcp(ref stream) => stream,
#[cfg(feature = "async-secure")]
DataStream::Ssl(ref stream) => stream.get_ref(),
}
}
}

// -- async

impl Read for DataStream {
impl<T> Read for DataStream<T>
where
T: AsyncTlsStream,
{
fn poll_read(
self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
buf: &mut [u8],
) -> std::task::Poll<Result<usize>> {
match self.project() {
DataStreamProj::Tcp(stream) => stream.poll_read(cx, buf),
#[cfg(feature = "async-secure")]
DataStreamProj::Ssl(stream) => stream.poll_read(cx, buf),
}
}
}

impl Write for DataStream {
impl<T> Write for DataStream<T>
where
T: AsyncTlsStream,
{
fn poll_write(
self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
buf: &[u8],
) -> std::task::Poll<Result<usize>> {
match self.project() {
DataStreamProj::Tcp(stream) => stream.poll_write(cx, buf),
#[cfg(feature = "async-secure")]
DataStreamProj::Ssl(stream) => stream.poll_write(cx, buf),
}
}
Expand All @@ -78,7 +87,6 @@ impl Write for DataStream {
) -> std::task::Poll<Result<()>> {
match self.project() {
DataStreamProj::Tcp(stream) => stream.poll_flush(cx),
#[cfg(feature = "async-secure")]
DataStreamProj::Ssl(stream) => stream.poll_flush(cx),
}
}
Expand All @@ -89,7 +97,6 @@ impl Write for DataStream {
) -> std::task::Poll<Result<()>> {
match self.project() {
DataStreamProj::Tcp(stream) => stream.poll_close(cx),
#[cfg(feature = "async-secure")]
DataStreamProj::Ssl(stream) => stream.poll_close(cx),
}
}
Expand Down
Loading

0 comments on commit 7b252ed

Please sign in to comment.