mirror of
https://github.com/mickael-kerjean/filestash.git
synced 2024-04-21 12:32:08 +00:00
fix (ftp): recreate connection if closed
An issue would araise when the connection is closed before we had time to do the vacuum cleaning on servers like on infinity free where "Our server has quite aggressive inactivity timeouts and will kill the connection after only 20 seconds of inactivity." reference: https://forum.infinityfree.net/t/good-online-ftp/69285/18
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package plg_backend_ftp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
@@ -47,7 +48,7 @@ func (f Ftp) Init(params map[string]string, app *App) (IBackend, error) {
|
||||
if c := FtpCache.Get(params); c != nil {
|
||||
d := c.(*Ftp)
|
||||
if d == nil {
|
||||
Log.Warning("plg_backend_ftp::sftp is nil on get")
|
||||
Log.Warning("plg_backend_ftp::ftp is nil on get")
|
||||
return nil, ErrInternal
|
||||
} else if d.wg == nil {
|
||||
Log.Warning("plg_backend_ftp::wg is nil on get")
|
||||
@@ -246,31 +247,50 @@ func (f Ftp) Meta(path string) Metadata {
|
||||
return Metadata{}
|
||||
}
|
||||
|
||||
func (f Ftp) Home() (string, error) {
|
||||
return f.client.Getwd()
|
||||
func (f Ftp) Home() (home string, err error) {
|
||||
f.Execute(func(client *goftp.Client) error {
|
||||
home, err = f.client.Getwd()
|
||||
return err
|
||||
})
|
||||
return home, err
|
||||
}
|
||||
|
||||
func (f Ftp) Ls(path string) ([]os.FileInfo, error) {
|
||||
return f.client.ReadDir(path)
|
||||
func (f Ftp) Ls(path string) (files []os.FileInfo, err error) {
|
||||
f.Execute(func(client *goftp.Client) error {
|
||||
files, err = client.ReadDir(path)
|
||||
return err
|
||||
})
|
||||
return files, err
|
||||
}
|
||||
|
||||
func (f Ftp) Cat(path string) (io.ReadCloser, error) {
|
||||
pr, pw := io.Pipe()
|
||||
go func() {
|
||||
if err := f.client.Retrieve(path, pw); err != nil {
|
||||
pr.CloseWithError(NewError("Problem", 409))
|
||||
func (f Ftp) Cat(path string) (reader io.ReadCloser, err error) {
|
||||
f.Execute(func(client *goftp.Client) error {
|
||||
if _, err = client.Stat(path); err != nil {
|
||||
return err
|
||||
}
|
||||
pw.Close()
|
||||
}()
|
||||
return pr, nil
|
||||
pr, pw := io.Pipe()
|
||||
go func() {
|
||||
err = client.Retrieve(path, pw)
|
||||
if err != nil {
|
||||
pr.CloseWithError(NewError("Problem", 409))
|
||||
}
|
||||
pw.Close()
|
||||
}()
|
||||
reader = pr
|
||||
return nil
|
||||
})
|
||||
return reader, err
|
||||
}
|
||||
|
||||
func (f Ftp) Mkdir(path string) error {
|
||||
_, err := f.client.Mkdir(path)
|
||||
func (f Ftp) Mkdir(path string) (err error) {
|
||||
f.Execute(func(client *goftp.Client) error {
|
||||
_, err = client.Mkdir(path)
|
||||
return err
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (f Ftp) Rm(path string) error {
|
||||
func (f Ftp) Rm(path string) (err error) {
|
||||
isDirectory := func(p string) bool {
|
||||
return regexp.MustCompile(`\/$`).MatchString(p)
|
||||
}
|
||||
@@ -287,43 +307,77 @@ func (f Ftp) Rm(path string) error {
|
||||
}
|
||||
return e
|
||||
}
|
||||
if isDirectory(path) {
|
||||
entries, err := f.Ls(path)
|
||||
if transformError(err) != nil {
|
||||
return err
|
||||
}
|
||||
for _, entry := range entries {
|
||||
if entry.IsDir() {
|
||||
err = f.Rm(path + entry.Name() + "/")
|
||||
if transformError(err) != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err = f.Rm(path + entry.Name())
|
||||
if transformError(err) != nil {
|
||||
return err
|
||||
var recursiveDelete func(client *goftp.Client, _path string) error
|
||||
recursiveDelete = func(client *goftp.Client, _path string) error {
|
||||
if isDirectory(_path) {
|
||||
entries, err := client.ReadDir(_path)
|
||||
if transformError(err) != nil {
|
||||
return err
|
||||
}
|
||||
for _, entry := range entries {
|
||||
if entry.IsDir() {
|
||||
err = recursiveDelete(client, _path+entry.Name()+"/")
|
||||
if transformError(err) != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err = recursiveDelete(client, _path+entry.Name())
|
||||
if transformError(err) != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
err = client.Rmdir(_path)
|
||||
return transformError(err)
|
||||
}
|
||||
err = f.client.Rmdir(path)
|
||||
err = client.Delete(_path)
|
||||
return transformError(err)
|
||||
}
|
||||
err := f.client.Delete(path)
|
||||
return transformError(err)
|
||||
f.Execute(func(client *goftp.Client) error {
|
||||
err = recursiveDelete(client, path)
|
||||
return err
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (f Ftp) Mv(from string, to string) error {
|
||||
return f.client.Rename(from, to)
|
||||
func (f Ftp) Mv(from string, to string) (err error) {
|
||||
f.Execute(func(client *goftp.Client) error {
|
||||
err = client.Rename(from, to)
|
||||
return err
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (f Ftp) Touch(path string) error {
|
||||
return f.client.Store(path, strings.NewReader(""))
|
||||
func (f Ftp) Touch(path string) (err error) {
|
||||
f.Execute(func(client *goftp.Client) error {
|
||||
err = client.Store(path, strings.NewReader(""))
|
||||
return err
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (f Ftp) Save(path string, file io.Reader) error {
|
||||
return f.client.Store(path, file)
|
||||
func (f Ftp) Save(path string, file io.Reader) (err error) {
|
||||
f.Execute(func(client *goftp.Client) error {
|
||||
err = client.Store(path, file)
|
||||
return err
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (f Ftp) Close() error {
|
||||
return f.client.Close()
|
||||
}
|
||||
|
||||
func (f Ftp) Execute(fn func(*goftp.Client) error) {
|
||||
err := fn(f.client)
|
||||
if ftpErr, ok := err.(goftp.Error); ok {
|
||||
code := ftpErr.Code()
|
||||
if code == 421 || (code == 0 && err.Error() == "error reading response: EOF") {
|
||||
f.Close()
|
||||
FtpCache.Set(f.p, nil)
|
||||
if b, err := f.Init(f.p, &App{Context: context.Background()}); err == nil {
|
||||
fn(b.(*Ftp).client)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user