server/admin/api/file.go

155 lines
3.7 KiB
Go

package api
import (
"bufio"
"encoding/base32"
"encoding/hex"
"errors"
"fmt"
"log"
"net/http"
"os"
"path"
"strings"
"srs.epita.fr/fic-server/libfic"
"github.com/dchest/blake2b"
)
var CloudDAVBase string
var CloudUsername string
var CloudPassword string
var RapidImport bool
type uploadedFile struct {
URI string
Digest string
Path string
Parts []string
}
func importFile(uf uploadedFile, next func(string, string, []byte) (interface{}, error)) (interface{}, error) {
var hash [blake2b.Size]byte
var logStr string
var fromURI string
var getFile func(string) error
if uf.URI != "" && len(uf.Parts) > 0 {
hash = blake2b.Sum512([]byte(uf.URI))
logStr = fmt.Sprintf("Import file from Cloud: %s =>", uf.Parts)
fromURI = uf.URI
getFile = func(dest string) error {
if fdto, err := os.Create(dest); err != nil {
return err
} else {
writer := bufio.NewWriter(fdto)
for _, partname := range uf.Parts {
if err := getCloudPart(partname, writer); err != nil {
return err
}
}
fdto.Close()
}
return nil
}
} else if uf.URI != "" {
hash = blake2b.Sum512([]byte(uf.URI))
logStr = "Import file from Cloud: " + uf.URI + " =>"
fromURI = uf.URI
getFile = func(dest string) error { return getCloudFile(uf.URI, dest) }
} else if uf.Path != "" && len(uf.Parts) > 0 {
hash = blake2b.Sum512([]byte(uf.Path))
logStr = fmt.Sprintf("Import file from local FS: %s =>", uf.Parts)
fromURI = uf.Path
getFile = func(dest string) error {
if fdto, err := os.Create(dest); err != nil {
return err
} else {
writer := bufio.NewWriter(fdto)
for _, partname := range uf.Parts {
if fdfrm, err := os.Open(partname); err != nil {
return err
} else {
reader := bufio.NewReader(fdfrm)
reader.WriteTo(writer)
writer.Flush()
fdfrm.Close()
}
}
fdto.Close()
}
return nil
}
} else if uf.Path != "" {
hash = blake2b.Sum512([]byte(uf.Path))
logStr = "Import file from local FS: " + uf.Path + " =>"
fromURI = uf.Path
getFile = func(dest string) error { return os.Symlink(uf.Path, dest) }
} else {
return nil, errors.New("URI or path not filled")
}
pathname := path.Join(fic.FilesDir, strings.ToLower(base32.StdEncoding.WithPadding(0).EncodeToString(hash[:])), path.Base(fromURI))
// Remove the file if it exists
// TODO: check if this is symlink => remove to avoid File not found error after, because the file is writen at the adresse pointed.
if _, err := os.Stat(pathname); !os.IsNotExist(err) && !RapidImport {
if err := os.Remove(pathname); err != nil {
return nil, err
}
}
if _, err := os.Stat(pathname); os.IsNotExist(err) {
log.Println(logStr, pathname)
if err := os.MkdirAll(path.Dir(pathname), 0777); err != nil {
return nil, err
} else if err := getFile(pathname); err != nil {
return nil, err
}
}
if digest, err := hex.DecodeString(uf.Digest); err != nil {
return nil, err
} else {
return next(pathname, fromURI, digest)
}
}
func getCloudFile(pathname string, dest string) error {
if fd, err := os.Create(dest); err != nil {
return err
} else {
defer fd.Close()
writer := bufio.NewWriter(fd)
if err := getCloudPart(pathname, writer); err != nil {
return err
}
}
return nil
}
func getCloudPart(pathname string, writer *bufio.Writer) error {
client := http.Client{}
if req, err := http.NewRequest("GET", CloudDAVBase+pathname, nil); err != nil {
return err
} else {
req.SetBasicAuth(CloudUsername, CloudPassword)
if resp, err := client.Do(req); err != nil {
return err
} else {
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return errors.New(resp.Status)
} else {
reader := bufio.NewReader(resp.Body)
reader.WriteTo(writer)
writer.Flush()
}
}
}
return nil
}