// Copyright 2024 RustFS Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! SFTP protocol support for RustFS.
//!
//! Provides an SSH server with the SFTP file transfer subsystem enabled.
//! Each SFTP operation is translated into one or more S3 API calls against
//! the local RustFS object store via the StorageBackend trait.
//!
//! The module is feature-gated behind the sftp feature and is composed of
//! seven user-facing submodules:
//!
//! - config: configuration loading from environment variables, plus host
//!   key discovery and validation.
//! - constants: protocol limits, timeouts, and other named numeric values
//!   used by the server and driver.
//! - server: russh handler implementation, password authentication against
//!   IAM, and subsystem dispatch onto the SFTP driver.
//! - driver: SFTP operation handlers that translate each request into one
//!   or more S3 calls on the supplied storage backend.
//! - lifecycle: per-session activity record, the registry the accept loop
//!   walks, and the kernel TCP-state probe used by the watchdog.
//! - wedge_watchdog and fallback_watchdog: the per-session liveness
//!   watchdog. On target_os = "linux" wedge_watchdog observes both the
//!   SFTP-handler activity stamp and the TCP socket state. On other
//!   targets fallback_watchdog provides a silence-only backstop without
//!   the TCP-state probe.
//! - read_cache: per-handle in-memory read-ahead cache with a process-wide
//!   memory ceiling.
//!
//! Configuration contract. Thirteen RUSTFS_SFTP_* environment variables drive
//! the server: RUSTFS_SFTP_ENABLE, RUSTFS_SFTP_ADDRESS, RUSTFS_SFTP_HOST_KEY_DIR,
//! RUSTFS_SFTP_HOST_KEY_RELOAD_ENABLE, RUSTFS_SFTP_HOST_KEY_RELOAD_INTERVAL,
//! RUSTFS_SFTP_IDLE_TIMEOUT, RUSTFS_SFTP_PART_SIZE, RUSTFS_SFTP_READ_ONLY,
//! RUSTFS_SFTP_BANNER, RUSTFS_SFTP_HANDLES_PER_SESSION,
//! RUSTFS_SFTP_BACKEND_OP_TIMEOUT_SECS, RUSTFS_SFTP_READ_CACHE_WINDOW_BYTES,
//! RUSTFS_SFTP_READ_CACHE_TOTAL_MEM_BYTES. Defaults and validation bounds
//! live on the constants in the limits module.
//!
//! Architecture. Two cross-cutting subsystems backstop session reliability
//! and read throughput:
//!
//! - Session-liveness watchdog. Every accepted connection runs under a
//!   per-session watchdog. On Linux the watchdog observes both the
//!   SFTP-handler activity stamp and the kernel TCP state for the
//!   connection. Sessions silent at the SFTP layer while the kernel
//!   reports CLOSE_WAIT are cancelled in approximately 45 to 60
//!   seconds. On non-Linux targets the watchdog observes only the
//!   activity stamp and cancels at an inactivity ceiling on the order
//!   of 30 minutes.
//!
//! - Per-handle read cache. Each open File handle holds an in-memory
//!   buffer. On a cache miss the driver fetches a configurable byte
//!   window from the backend, returns the requested portion, and stores
//!   the rest. Subsequent reads inside that window are served from
//!   memory. Total cache memory across every live handle is bounded by
//!   a shared atomic accumulator enforced against the process-wide
//!   ceiling. On ceiling breach the population is skipped and the read
//!   serves correctly via a single backend call without storing the
//!   bytes for re-use.
//!
//! Authentication mirrors the S3 baseline: identities are looked up through
//! rustfs_iam and the supplied secret is compared in constant time against
//! the stored secret. Failures are logged via tracing warn and return an SSH
//! authentication rejection.
//!
//! Public types: SftpServer is the entry point an embedder constructs and
//! drives. SftpConfig and SftpInitError are the configuration and error
//! types returned by configuration loading. SftpDriver is the per-session
//! handler dispatch type. SftpError is the error type returned by SFTP
//! operations.
//!
//! Platform support. On Unix the host-key loader enforces owner-only mode
//! bits. On Windows it loads host keys without a mode check and trusts the
//! operator-managed NTFS ACLs on the key directory. On targets that are
//! neither Unix nor Windows, SftpConfig::load_host_keys returns
//! SftpInitError::UnsupportedPlatform and the SFTP listener does not start.
//!
//! Peer-initiated signal requests on an open SFTP channel are intercepted
//! by the russh::server::Handler::signal override on SshSessionHandler in
//! server.rs, which logs the probe and rejects without acting.

pub mod config;
pub(crate) mod constants;
pub mod server;

mod attrs;
mod dir;
mod driver;
mod errors;
#[cfg(not(target_os = "linux"))]
mod fallback_watchdog;
mod lifecycle;
mod paths;
mod read;
mod read_cache;
mod state;
#[cfg(target_os = "linux")]
mod wedge_watchdog;
mod write;

#[cfg(test)]
mod test_support;

pub use config::{SftpConfig, SftpInitError};
pub use driver::SftpDriver;
pub use errors::SftpError;
pub use server::SftpServer;

#[cfg(test)]
mod tests {
    use super::*;
    use crate::common::session::Protocol;

    // Compile-time check that Protocol::Sftp, SftpConfig, and SftpInitError
    // remain exported. Renaming or removing any of these breaks the test.
    #[test]
    fn sftp_module_and_variant_exist() {
        let _variant = Protocol::Sftp;
        let _config_type_name = std::any::type_name::<SftpConfig>();
        let _error_type_name = std::any::type_name::<SftpInitError>();
    }
}
