server/admin/sync/file.go
nemunaire 8f7de926d3 admin: Implement sychronization backends
We are now able, depending on configuration, to retrieve files from either WebDAV or local file system.
2018-01-17 18:52:39 +01:00

99 lines
2.1 KiB
Go

package sync
import (
"bufio"
"encoding/base32"
"errors"
"fmt"
"os"
"path"
"strings"
"srs.epita.fr/fic-server/libfic"
"github.com/dchest/blake2b"
)
type Importer interface {
Kind() string
exists(filename string) bool
toURL(filename string) string
getFile(filename string, writer *bufio.Writer) error
listDir(filename string) ([]string, error)
}
var GlobalImporter Importer
func getFile(i Importer, URI string, writer *bufio.Writer) error {
// Import file if it exists
if i.exists(URI) {
return i.getFile(URI, writer)
}
// Try to find file parts
dirname := path.Dir(URI)
if i.exists(dirname) {
filename := path.Base(URI)
if files, err := i.listDir(dirname); err != nil {
return err
} else {
for _, fname := range []string{filename, filename + "."} {
found := false
for _, file := range files {
if matched, _ := path.Match(fname + "[0-9][0-9]", file); matched {
found = true
if err := i.getFile(path.Join(dirname, file), writer); err != nil {
return err
}
}
}
if found {
return nil
}
}
}
}
return errors.New(fmt.Sprintf("%q: no such file or directory", i.toURL(URI)))
}
func ImportFile(URI string, next func(string, string) (interface{}, error)) (interface{}, error) {
hash := blake2b.Sum512([]byte(URI))
dest := path.Join(fic.FilesDir, strings.ToLower(base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(hash[:])), path.Base(URI))
// If the present file is still valide, don't erase it
if _, err := os.Stat(dest); !os.IsNotExist(err) {
if r, err := next(dest, URI); err == nil {
return r, err
}
if err := os.Remove(dest); err != nil {
return nil, err
}
}
// Ensure no more file is registered with this path
if f, err := fic.GetFileByPath(dest); err == nil {
f.Delete()
}
if err := os.MkdirAll(path.Dir(dest), 0755); err != nil {
return nil, err
}
// Write file
if fdto, err := os.Create(dest); err != nil {
return nil, err
} else {
defer fdto.Close()
writer := bufio.NewWriter(fdto)
if err := getFile(GlobalImporter, URI, writer); err != nil {
os.Remove(dest)
return nil, err
}
}
return next(dest, URI)
}