Documentation
¶
Overview ¶
Package ftpclient provides a thread-safe FTP client with automatic reconnection and connection pooling capabilities.
This package wraps the github.com/jlaffaye/ftp library with additional features:
- Thread-safe operations using atomic values and mutexes
- Automatic connection management with health checks (NOOP)
- Flexible configuration with TLS/SSL support
- Context-aware operations for timeout control
- Comprehensive error handling with custom error types
Architecture:
┌──────────────┐
│ FTPClient │ ← Public Interface
└──────────────┘
↓
┌──────────────┐
│ ftpClient │ ← Thread-safe implementation
│ (atomic) │
└──────────────┘
↓
┌──────────────┐
│ ServerConn │ ← Underlying FTP connection
└──────────────┘
Basic usage:
import (
"context"
"github.com/nabbar/golib/ftpclient"
)
cfg := &ftpclient.Config{
Hostname: "ftp.example.com:21",
Login: "user",
Password: "pass",
ConnTimeout: 30 * time.Second,
}
cfg.RegisterContext(func() context.Context {
return context.Background()
})
client, err := ftpclient.New(cfg)
if err != nil {
panic(err)
}
defer client.Close()
// Upload a file
file, _ := os.Open("local.txt")
defer file.Close()
err = client.Stor("remote.txt", file)
See the Config struct for all available configuration options.
Index ¶
Constants ¶
const ( ErrorParamsEmpty liberr.CodeError = iota + liberr.MinPkgFTPClient // Given parameters are empty ErrorValidatorError // Configuration validation failed ErrorEndpointParser // Cannot parse the given endpoint ErrorNotInitialized // Client instance is not initialized ErrorFTPConnection // Failed to establish FTP connection ErrorFTPConnectionCheck // Connection check (NOOP) failed ErrorFTPLogin // FTP login authentication failed ErrorFTPCommand // FTP command execution failed )
Error codes for FTP client operations. These errors are registered with the golib/errors package for consistent error handling.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config struct {
// Hostname define the host/port to connect to server.
Hostname string `mapstructure:"hostname" json:"hostname" yaml:"hostname" toml:"hostname" validate:"required,hostname_rfc1123"`
// Login define the login to use in login command.
Login string `mapstructure:"login" json:"login" yaml:"login" toml:"login"`
// Password defined the password to use in the login command.
Password string `mapstructure:"password" json:"password" yaml:"password" toml:"password"`
// ConnTimeout define a timeout duration for each connection (this is a global connection : connection, store contents, read content, ...).
ConnTimeout time.Duration `mapstructure:"conn_timeout" json:"conn_timeout" yaml:"conn_timeout" toml:"conn_timeout"`
// TimeZone force the time zone to use for the connection to the server.
TimeZone ConfigTimeZone `mapstructure:"timezone" json:"timezone" yaml:"timezone" toml:"timezone"`
// DisableUTF8 disable the UTF8 translation into the connection to the server.
DisableUTF8 bool `mapstructure:"disable_utf8" json:"disable_utf8" yaml:"disable_utf8" toml:"disable_utf8"`
// DisableEPSV disable the EPSV command into the connection to the server. (cf RFC 2428).
DisableEPSV bool `mapstructure:"disable_epsv" json:"disable_epsv" yaml:"disable_epsv" toml:"disable_epsv"`
// DisableMLSD disable the MLSD command into the connection to the server. (cf RFC 3659)
DisableMLSD bool `mapstructure:"disable_mlsd" json:"disable_mlsd" yaml:"disable_mlsd" toml:"disable_mlsd"`
// EnableMDTM enable the MDTM command into the connection to the server. (cf RFC 3659)
EnableMDTM bool `mapstructure:"enable_mdtm" json:"enable_mdtm" yaml:"enable_mdtm" toml:"enable_mdtm"`
// ForceTLS defined if the TLS connection must be forced or not.
ForceTLS bool `mapstructure:"force_tls" json:"force_tls" yaml:"force_tls" toml:"force_tls"`
// TLS define the client TLS config used if needed or forced
TLS libtls.Config `mapstructure:"tls" json:"tls" yaml:"tls" toml:"tls"`
// contains filtered or unexported fields
}
Config holds the FTP client configuration. It supports various FTP features including TLS, extended passive mode (EPSV), machine-readable listings (MLSD), and file modification time commands (MDTM/MFMT).
The configuration is validated using struct tags and the validator package. All public fields can be marshalled to/from JSON, YAML, TOML, and Viper config formats.
func (*Config) New ¶
func (c *Config) New() (*libftp.ServerConn, error)
New creates a new FTP server connection based on the current configuration. It applies all configured options including TLS, timeouts, timezone, and protocol features. The connection is established and authenticated (if credentials are provided) before returning.
Returns the established connection or an error if connection/authentication fails.
func (*Config) RegisterContext ¶
RegisterContext registers a function that provides context for FTP operations. This allows for timeout and cancellation support in long-running operations. If not registered, operations will not have context support.
func (*Config) RegisterDefaultTLS ¶
RegisterDefaultTLS registers a function that provides default TLS configuration. This is used as a fallback when the Config.TLS field is not set. The function should return a TLSConfig that will be used for secure connections.
type ConfigTimeZone ¶
type ConfigTimeZone struct {
Name string `mapstructure:"name" json:"name" yaml:"name" toml:"name"` // Timezone name (e.g., "America/New_York", "UTC")
Offset int `mapstructure:"offset" json:"offset" yaml:"offset" toml:"offset"` // Offset in seconds from UTC
}
ConfigTimeZone defines the timezone configuration for FTP file timestamps. The offset is specified in seconds from UTC.
type FTPClient ¶
type FTPClient interface {
// Connect establish the connection to server with the given configuration registered.
Connect() error
// Check try to retrieve a valid connection to the server and send an NOOP command to check the connection.
Check() error
// Close send the QUID command to the server if the connection is valid (cf Check).
Close()
// NameList issues an NLST FTP command.
NameList(path string) ([]string, error)
// List issues a LIST FTP command.
List(path string) ([]*libftp.Entry, error)
// ChangeDir issues a CWD FTP command, which changes the current directory to the specified path.
ChangeDir(path string) error
// CurrentDir issues a PWD FTP command, which Returns the path of the current directory.
CurrentDir() (string, error)
// FileSize issues a SIZE FTP command, which Returns the size of the file.
FileSize(path string) (int64, error)
// GetTime issues the MDTM FTP command to obtain the file modification time.
// It returns a UTC time.
GetTime(path string) (time.Time, error)
// SetTime issues the MFMT FTP command to set the file modification time.
// Also it can use a non-standard form of the MDTM command supported by the VsFtpd server instead of MFMT for the same purpose.
// See "mdtm_write" in https://security.appspot.com/vsftpd/vsftpd_conf.html
SetTime(path string, t time.Time) error
// Retr issues a RETR FTP command to fetch the specified file from the remote FTP server.
// The returned ReadCloser must be closed to cleanup the FTP data connection.
Retr(path string) (*libftp.Response, error)
// RetrFrom issues a RETR FTP command to fetch the specified file from the remote FTP server,
// the server will not send the offset first bytes of the file.
// The returned ReadCloser must be closed to cleanup the FTP data connection.
RetrFrom(path string, offset uint64) (*libftp.Response, error)
// Stor issues a STOR FTP command to store a file to the remote FTP server.
// Stor creates the specified file with the content of the io.Reader.
// Hint: io.Pipe() can be used if an io.Writer is required.
Stor(path string, r io.Reader) error
// StorFrom issues a STOR FTP command to store a file to the remote FTP server.
// Stor creates the specified file with the content of the io.Reader, writing on the server will start at the given file offset.
// Hint: io.Pipe() can be used if an io.Writer is required.
StorFrom(path string, r io.Reader, offset uint64) error
// Append issues a APPE FTP command to store a file to the remote FTP server.
// If a file already exists with the given path, then the content of the io.Reader is appended.
// Otherwise, a new file is created with that content. Hint: io.Pipe() can be used if an io.Writer is required.
Append(path string, r io.Reader) error
// Rename renames a file on the remote FTP server.
Rename(from, to string) error
// Delete issues a DELE FTP command to delete the specified file from the remote FTP server.
Delete(path string) error
// RemoveDirRecur deletes a non-empty folder recursively using RemoveDir and Delete.
RemoveDirRecur(path string) error
// MakeDir issues a MKD FTP command to create the specified directory on the remote FTP server.
MakeDir(path string) error
// RemoveDir issues a RMD FTP command to remove the specified directory from the remote FTP server.
RemoveDir(path string) error
//Walk prepares the internal walk function so that the caller can begin traversing the directory.
Walk(root string) (*libftp.Walker, error)
}
FTPClient defines the interface for FTP operations. All methods are thread-safe and handle connection management automatically. Failed connections will be automatically re-established on the next operation.
func New ¶
New creates a new FTP client instance with the given configuration. It immediately attempts to connect and validate the connection using a NOOP command.
The client uses atomic operations for thread-safe configuration and connection management. If the initial connection fails, an error is returned and the client is nil.
Example:
cfg := &Config{
Hostname: "ftp.example.com:21",
Login: "user",
Password: "pass",
}
client, err := New(cfg)
if err != nil {
log.Fatal(err)
}
defer client.Close()