veeso / suppaftp

a super FTP/FTPS client library for Rust with support for both passive and active mode
Apache License 2.0
121 stars 31 forks source link

[Feature Request] Allow interchangeable use of stream types by exposing ImplFtpStream #40

Closed svet-b closed 1 year ago

svet-b commented 1 year ago

Description

I'd like to do something like

pub fn connect(addr: &str, user: &str, password: &str, secure: bool) -> FtpResult<ImplFtpStream> {
    let mut ftp_stream = match secure {
        false => init_plain_stream(addr)?,
        true => init_secure_stream(addr)?,
    };
    ftp_stream.login(user, password)?;
    Ok(ftp_stream)
}

where init_plain_stream() and init_secure_stream() respectively return FtpStream and NativeTlsFtpStream using the connect()/into_secure() calls outlined in the documentation.

Basically my desire is to establish the connection once - going through the appropriate steps to secure it, or not - and then use it as a generic stream afterwards. In terms of function signatures I feel like I should be able to achieve this by using the ImplFtpStream struct that's common across connection types. But this is currently set to private.

Is what I'm thinking likely to work? And if so, would it be possible to make the generic ImplFtpStream struct public?

By the way, if there are other ways to do this I'd be quite happy to reconsider my approach! I'm fairly new to Rust. (Also I'm aware that the match statement in my example code won't work as is anyway since the types of the arms need to match, but that's solvable).

Changes

Make ImplFtpStream public?

veeso commented 1 year ago

That's a good point. Made it public in 5.1.1

svet-b commented 1 year ago

Thanks a lot for the quick response to this! I had a go at doing what I need to do with the new version but somehow didn't quite get it to work. I'm sure this will expose my ignorance when it comes to some Rust concepts, but since ImplFtpStream is actually a struct and not a trait, I'm not able to use it as a dyn type.

Is there a way to write code that will set up an ftp_stream that is generic over ImplFtpStream (regardless of whether the encapsulated stream is secure or not) and can then carry out the login() and other methods that are common to both types of connection? Sorry if I'm missing something simple...

svet-b commented 1 year ago

FWIW I wrote a bit about my attempts to do this, and got some advice on the user forum here: https://users.rust-lang.org/t/more-elegant-way-to-call-generic-methods-on-a-struct/92397

veeso commented 1 year ago

Probably a trait would be needed, but it's not that easy to implement here.

Anyway at the time I didn't think much about your request, but there's no need to use the plain FTP stream if secure is enabled. You can just use the RustlsFtpStream or NativeTlsFtpStream and call into_secure only if secure = true

svet-b commented 1 year ago

Oh wow, that's a very good point! Didn't occur to me to try that at all. Seems to work perfectly also.