admin: Implement sychronization backends
We are now able, depending on configuration, to retrieve files from either WebDAV or local file system.
This commit is contained in:
parent
b701aa1710
commit
dddf72267d
7 changed files with 281 additions and 160 deletions
98
admin/sync/file.go
Normal file
98
admin/sync/file.go
Normal file
|
@ -0,0 +1,98 @@
|
|||
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)
|
||||
}
|
Reference in a new issue