server/core/driver.go
Nick Craig-Wood c28a288338
Some checks failed
continuous-integration/drone/push Build is failing
Factor into server and driver directories (#120)
Factor into core and driver directories

The change factors the pure server implementation into the "core"
directory and factors the file driver into "driver/file" and the minio
driver into "driver/minio".

This means that users of this library can import goftp.io/server/core
without having to import the file and minio drivers which may not be
needed.

This also adds a compatibility layer which exports all the types,
functions and variables that were exported at the top level.

This means this change should be 100% backwards compatible.

Fixes #116

Co-authored-by: Nick Craig-Wood <nick@craig-wood.com>
Reviewed-on: #120
2020-07-07 16:02:27 +00:00

163 lines
4.9 KiB
Go

// Copyright 2018 The goftp Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package core
import (
"errors"
"io"
"strings"
)
// DriverFactory is a driver factory to create driver. 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 DriverFactory interface {
NewDriver() (Driver, error)
}
// Driver is an interface that you will implement to create a driver for your
// chosen persistence layer. The server will create a new instance of your
// driver for each client that connects and delegate to it as required.
//
// Note that if the driver also implements the Auth interface then
// this will be called instead of calling ServerOpts.Auth. This allows
// the Auth mechanism to change the driver configuration.
type Driver interface {
// 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
Stat(string) (FileInfo, error)
// params - path, function on file or subdir found
// returns - error
// path
ListDir(string, func(FileInfo) error) error
// params - path
// returns - nil if the directory was deleted or any error encountered
DeleteDir(string) error
// params - path
// returns - nil if the file was deleted or any error encountered
DeleteFile(string) error
// params - from_path, to_path
// returns - nil if the file was renamed or any error encountered
Rename(string, string) error
// params - path
// returns - nil if the new directory was created or any error encountered
MakeDir(string) error
// params - path
// returns - a string containing the file data to send to the client
GetFile(string, int64) (int64, io.ReadCloser, error)
// params - destination path, an io.Reader containing the file data
// returns - the number of bytes writen and the first error encountered while writing, if any.
PutFile(string, io.Reader, bool) (int64, error)
}
var _ Driver = &MultipleDriver{}
// MultipleDriver represents a composite driver
type MultipleDriver struct {
drivers map[string]Driver
}
// Stat implements Driver
func (driver *MultipleDriver) Stat(path string) (FileInfo, error) {
for prefix, driver := range driver.drivers {
if strings.HasPrefix(path, prefix) {
return driver.Stat(strings.TrimPrefix(path, prefix))
}
}
return nil, errors.New("Not a file")
}
// ListDir implements Driver
func (driver *MultipleDriver) ListDir(path string, callback func(FileInfo) error) error {
for prefix, driver := range driver.drivers {
if strings.HasPrefix(path, prefix) {
return driver.ListDir(strings.TrimPrefix(path, prefix), callback)
}
}
return errors.New("Not a directory")
}
// DeleteDir implements Driver
func (driver *MultipleDriver) DeleteDir(path string) error {
for prefix, driver := range driver.drivers {
if strings.HasPrefix(path, prefix) {
return driver.DeleteDir(strings.TrimPrefix(path, prefix))
}
}
return errors.New("Not a directory")
}
// DeleteFile implements Driver
func (driver *MultipleDriver) DeleteFile(path string) error {
for prefix, driver := range driver.drivers {
if strings.HasPrefix(path, prefix) {
return driver.DeleteFile(strings.TrimPrefix(path, prefix))
}
}
return errors.New("Not a file")
}
// Rename implements Driver
func (driver *MultipleDriver) Rename(fromPath string, toPath string) error {
for prefix, driver := range driver.drivers {
if strings.HasPrefix(fromPath, prefix) {
return driver.Rename(strings.TrimPrefix(fromPath, prefix), strings.TrimPrefix(toPath, prefix))
}
}
return errors.New("Not a file")
}
// MakeDir implements Driver
func (driver *MultipleDriver) MakeDir(path string) error {
for prefix, driver := range driver.drivers {
if strings.HasPrefix(path, prefix) {
return driver.MakeDir(strings.TrimPrefix(path, prefix))
}
}
return errors.New("Not a directory")
}
// GetFile implements Driver
func (driver *MultipleDriver) GetFile(path string, offset int64) (int64, io.ReadCloser, error) {
for prefix, driver := range driver.drivers {
if strings.HasPrefix(path, prefix) {
return driver.GetFile(strings.TrimPrefix(path, prefix), offset)
}
}
return 0, nil, errors.New("Not a file")
}
// PutFile implements Driver
func (driver *MultipleDriver) PutFile(destPath string, data io.Reader, appendData bool) (int64, error) {
for prefix, driver := range driver.drivers {
if strings.HasPrefix(destPath, prefix) {
return driver.PutFile(strings.TrimPrefix(destPath, prefix), data, appendData)
}
}
return 0, errors.New("Not a file")
}
// MultipleDriverFactory implements a DriverFactory
type MultipleDriverFactory struct {
drivers map[string]Driver
}
// NewDriver implements DriverFactory
func (factory *MultipleDriverFactory) NewDriver() (Driver, error) {
return &MultipleDriver{factory.drivers}, nil
}