113 lines
2.5 KiB
Go
113 lines
2.5 KiB
Go
package sync
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"encoding/base32"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path"
|
|
"strings"
|
|
|
|
"srs.epita.fr/fic-server/libfic"
|
|
|
|
"golang.org/x/crypto/blake2b"
|
|
)
|
|
|
|
type Importer interface {
|
|
Kind() string
|
|
exists(filename string) bool
|
|
toURL(filename string) string
|
|
importFile(URI string, next func(string, string) (interface{}, error)) (interface{}, error)
|
|
getFile(filename string, writer *bufio.Writer) error
|
|
listDir(filename string) ([]string, error)
|
|
stat(filename string) (os.FileInfo, 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", URI))
|
|
}
|
|
|
|
func getFileContent(i Importer, URI string) (string, error) {
|
|
cnt := bytes.Buffer{}
|
|
|
|
if err := getFile(i, URI, bufio.NewWriter(io.Writer(&cnt))); err != nil {
|
|
return "", err
|
|
} else {
|
|
return strings.TrimSpace(cnt.String()), nil
|
|
}
|
|
}
|
|
|
|
func getDestinationFilePath(URI string) string {
|
|
hash := blake2b.Sum512([]byte(URI))
|
|
return path.Join(fic.FilesDir, strings.ToLower(base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(hash[:])), path.Base(URI))
|
|
}
|
|
|
|
func ImportFile(i Importer, URI string, next func(string, string) (interface{}, error)) (interface{}, error) {
|
|
dest := getDestinationFilePath(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
|
|
}
|
|
}
|
|
|
|
// 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(i, URI, writer); err != nil {
|
|
os.Remove(dest)
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
return next(dest, URI)
|
|
}
|