remote-fs 0.1.0

Unified async file operations over SMB, FTP, and SFTP
Documentation
use std::path::PathBuf;
use std::time::SystemTime;

/// Supported remote protocols.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Protocol {
    Smb,
    Ftp,
    Sftp,
}

/// File or directory entry returned by listing.
#[derive(Debug, Clone)]
pub struct FileEntry {
    pub path: PathBuf,
    pub name: String,
    pub is_dir: bool,
    pub is_file: bool,
    pub is_symlink: bool,
    pub size: u64,
    pub modified: Option<SystemTime>,
}

/// Metadata for a remote path.
#[derive(Debug, Clone)]
pub struct FileMeta {
    pub path: PathBuf,
    pub is_dir: bool,
    pub is_file: bool,
    pub is_symlink: bool,
    pub size: u64,
    pub modified: Option<SystemTime>,
}

/// SMB connection configuration.
#[derive(Debug, Clone)]
pub struct SmbConfig {
    pub host: String,
    pub share: String,
    pub username: String,
    pub password: String,
    pub port: Option<u16>,
    pub workgroup: Option<String>,
}

impl SmbConfig {
    pub fn new(
        host: impl Into<String>,
        share: impl Into<String>,
        username: impl Into<String>,
        password: impl Into<String>,
    ) -> Self {
        Self {
            host: host.into(),
            share: share.into(),
            username: username.into(),
            password: password.into(),
            port: None,
            workgroup: None,
        }
    }

    pub fn port(mut self, port: u16) -> Self {
        self.port = Some(port);
        self
    }

    pub fn workgroup(mut self, workgroup: impl Into<String>) -> Self {
        self.workgroup = Some(workgroup.into());
        self
    }
}

/// FTP connection configuration.
#[derive(Debug, Clone)]
pub struct FtpConfig {
    pub host: String,
    pub port: u16,
    pub username: String,
    pub password: String,
    pub passive: bool,
}

impl FtpConfig {
    pub fn new(
        host: impl Into<String>,
        username: impl Into<String>,
        password: impl Into<String>,
    ) -> Self {
        Self {
            host: host.into(),
            port: 21,
            username: username.into(),
            password: password.into(),
            passive: true,
        }
    }

    pub fn port(mut self, port: u16) -> Self {
        self.port = port;
        self
    }

    pub fn passive(mut self, passive: bool) -> Self {
        self.passive = passive;
        self
    }
}

/// SFTP connection configuration.
#[derive(Debug, Clone)]
pub struct SftpConfig {
    pub host: String,
    pub port: u16,
    pub username: String,
    pub password: Option<String>,
    pub private_key_path: Option<PathBuf>,
}

impl SftpConfig {
    pub fn with_password(
        host: impl Into<String>,
        username: impl Into<String>,
        password: impl Into<String>,
    ) -> Self {
        Self {
            host: host.into(),
            port: 22,
            username: username.into(),
            password: Some(password.into()),
            private_key_path: None,
        }
    }

    pub fn with_key(
        host: impl Into<String>,
        username: impl Into<String>,
        private_key_path: impl Into<PathBuf>,
    ) -> Self {
        Self {
            host: host.into(),
            port: 22,
            username: username.into(),
            password: None,
            private_key_path: Some(private_key_path.into()),
        }
    }

    pub fn port(mut self, port: u16) -> Self {
        self.port = port;
        self
    }
}

/// Generic connection configuration.
#[derive(Debug, Clone)]
pub enum Config {
    Smb(SmbConfig),
    Ftp(FtpConfig),
    Sftp(SftpConfig),
}

impl Config {
    pub fn protocol(&self) -> Protocol {
        match self {
            Config::Smb(_) => Protocol::Smb,
            Config::Ftp(_) => Protocol::Ftp,
            Config::Sftp(_) => Protocol::Sftp,
        }
    }
}