Documentation ¶
Overview ¶
An example FTP server build on top of go-raval. graval handles the details of the FTP protocol, we just provide a basic in-memory persistence driver.
If you're looking to create a custom graval driver, this example is a reasonable starting point. I suggest copying this file and changing the function bodies as required.
USAGE:
go get github.com/yob/graval go install github.com/yob/graval/graval-mem ./bin/graval-mem
An experimental FTP server framework. By providing a simple driver class that responds to a handful of methods you can have a complete FTP server.
Some sample use cases include persisting data to an Amazon S3 bucket, a relational database, redis or memory.
There is a sample in-memory driver available - see the documentation for the graval-mem package or the graval READEME for more details.
Index ¶
- func NewDirItem(name string, modtime time.Time) os.FileInfo
- func NewFileItem(name string, bytes int64, modtime time.Time) os.FileInfo
- type FTPDriver
- type FTPDriverFactory
- type FTPServer
- type FTPServerOpts
- type MemDriver
- func (driver *MemDriver) Authenticate(user string, pass string) bool
- func (driver *MemDriver) Bytes(path string) (bytes int64)
- func (driver *MemDriver) ChangeDir(path string) bool
- func (driver *MemDriver) DeleteDir(path string) bool
- func (driver *MemDriver) DeleteFile(path string) bool
- func (driver *MemDriver) DirContents(path string) (files []os.FileInfo)
- func (driver *MemDriver) GetFile(path string) (reader io.ReadCloser, err error)
- func (driver *MemDriver) MakeDir(path string) bool
- func (driver *MemDriver) ModifiedTime(path string) (time.Time, error)
- func (driver *MemDriver) PutFile(destPath string, data io.Reader) bool
- func (driver *MemDriver) Rename(fromPath string, toPath string) bool
- type MemDriverFactory
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func NewDirItem ¶
NewDirItem creates a new os.FileInfo that represents a single diretory. Use this function to build the response to DirContents() in your FTPDriver implementation.
Types ¶
type FTPDriver ¶
type FTPDriver interface { // params - username, password // returns - true if the provided details are valid Authenticate(string, string) bool // params - a file path // returns - an int with the number of bytes in the file or -1 if the file // doesn't exist Bytes(string) int64 // params - a file path // returns - a time indicating when the requested path was last modified // - an error if the file doesn't exist or the user lacks // permissions ModifiedTime(string) (time.Time, error) // params - path // returns - true if the current user is permitted to change to the // requested path ChangeDir(string) bool // params - path // returns - a collection of items describing the contents of the requested // path DirContents(string) []os.FileInfo // params - path // returns - true if the directory was deleted DeleteDir(string) bool // params - path // returns - true if the file was deleted DeleteFile(string) bool // params - from_path, to_path // returns - true if the file was renamed Rename(string, string) bool // params - path // returns - true if the new directory was created MakeDir(string) bool // params - path // returns - a Reader that will return file data to send to the client GetFile(string) (io.ReadCloser, error) // params - desination path, an io.Reader containing the file data // returns - true if the data was successfully persisted PutFile(string, io.Reader) bool }
You will create an implementation of this interface that speaks to your chosen persistence layer. graval will create a new instance of your driver for each client that connects and delegate to it as required.
type FTPDriverFactory ¶
For each client that connects to the server, a new FTPDriver is required. Create an implementation if this interface and provide it to FTPServer.
type FTPServer ¶
type FTPServer struct {
// contains filtered or unexported fields
}
FTPServer is the root of your FTP application. You should instantiate one of these and call ListenAndServe() to start accepting client connections.
Always use the NewFTPServer() method to create a new FTPServer.
func NewFTPServer ¶
func NewFTPServer(opts *FTPServerOpts) *FTPServer
NewFTPServer initialises a new FTP server. Configuration options are provided via an instance of FTPServerOpts. Calling this function in your code will probably look something like this:
factory := &MyDriverFactory{} server := graval.NewFTPServer(&graval.FTPServerOpts{ Factory: factory })
or:
factory := &MyDriverFactory{} opts := &graval.FTPServerOpts{ Factory: factory, Port: 2000, Hostname: "127.0.0.1", } server := graval.NewFTPServer(opts)
func (*FTPServer) ListenAndServe ¶
ListenAndServe asks a new FTPServer to begin accepting client connections. It accepts no arguments - all configuration is provided via the NewFTPServer function.
If the server fails to start for any reason, an error will be returned. Common errors are trying to bind to a privileged port or something else is already listening on the same port.
type FTPServerOpts ¶
type FTPServerOpts struct { // Server name will be used for welcome message ServerName string // The factory that will be used to create a new FTPDriver instance for // each client connection. This is a mandatory option. Factory FTPDriverFactory // The hostname that the FTP server should listen on. Optional, defaults to // "::", which means all hostnames on ipv4 and ipv6. Hostname string // The port that the FTP should listen on. Optional, defaults to 3000. In // a production environment you will probably want to change this to 21. Port int // The lower bound of port numbers that can be used for passive-mode data sockets // Defaults to 0, which allows the server to pick any free port PasvMinPort int // The upper bound of port numbers that can be used for passive-mode data sockets // Defaults to 0, which allows the server to pick any free port PasvMaxPort int // Use this option to override the IP address that will be advertised in response to the // PASV command. Most setups can ignore this, but it can be helpful in situations where // the FTP server is behind a NAT gateway or load balancer and the public IP used by // clients is different to the IP the server is directly listening on PasvAdvertisedIp string }
serverOpts contains parameters for graval.NewFTPServer()
type MemDriver ¶
type MemDriver struct{}
A minimal driver for graval that stores everything in memory. The authentication details are fixed and the user is unable to upload, delete or rename any files.
This really just exists as a minimal demonstration of the interface graval drivers are required to implement.
func (*MemDriver) Authenticate ¶
func (*MemDriver) DeleteFile ¶
func (*MemDriver) DirContents ¶
func (*MemDriver) GetFile ¶
func (driver *MemDriver) GetFile(path string) (reader io.ReadCloser, err error)
func (*MemDriver) ModifiedTime ¶
type MemDriverFactory ¶
type MemDriverFactory struct{}
graval requires a factory that will create a new driver instance for each client connection. Generally the factory will be fairly minimal. This is a good place to read any required config for your driver.
func (*MemDriverFactory) NewDriver ¶
func (factory *MemDriverFactory) NewDriver() (FTPDriver, error)