package sync import ( "bufio" "bytes" "encoding/base32" "errors" "fmt" "io" "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 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 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) }