feat: add file copy and rename
This commit is contained in:
parent
d83ad12683
commit
f02b72e766
6
Makefile
6
Makefile
@ -30,6 +30,11 @@ else
|
|||||||
GOOS=linux GOARCH=amd64 go build -ldflags "$(LDFLAGS)" -o $(BINARY_NAME) ./
|
GOOS=linux GOARCH=amd64 go build -ldflags "$(LDFLAGS)" -o $(BINARY_NAME) ./
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
.PHONY: build-linux
|
||||||
|
build-linux:
|
||||||
|
@echo "Building for Linux..."
|
||||||
|
GOOS=linux GOARCH=amd64 go build -ldflags "$(LDFLAGS)" -o $(BINARY_NAME) ./
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
rm -f $(BINARY_NAME)
|
rm -f $(BINARY_NAME)
|
||||||
@ -41,4 +46,5 @@ help:
|
|||||||
@echo " all - Generate protobuf files and build for current platform (default)"
|
@echo " all - Generate protobuf files and build for current platform (default)"
|
||||||
@echo " proto - Generate protobuf files"
|
@echo " proto - Generate protobuf files"
|
||||||
@echo " build - Build for current platform"
|
@echo " build - Build for current platform"
|
||||||
|
@echo " build-linux - Build for linux platform"
|
||||||
@echo " clean - Remove built binaries and generated protobuf files"
|
@echo " clean - Remove built binaries and generated protobuf files"
|
||||||
|
|||||||
11
api_file.go
11
api_file.go
@ -148,5 +148,16 @@ func (s *Service) HandleCopyFile(
|
|||||||
req *httpserver.Request,
|
req *httpserver.Request,
|
||||||
resp *httpserver.Response,
|
resp *httpserver.Response,
|
||||||
) *httpserver.Response {
|
) *httpserver.Response {
|
||||||
|
params := req.Binded.(*CopyParams)
|
||||||
|
isDir := params.IsDir
|
||||||
|
srcPath := utils.FullPath(utils.NormalizePath(params.SrcPath))
|
||||||
|
dstPath := utils.FullPath(utils.NormalizePath(params.DstPath))
|
||||||
|
|
||||||
|
err := s.FileSystemManager.CopyFile(req.Context(), srcPath, dstPath, isDir)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("copy %s to %s: %v", srcPath, dstPath, err)
|
||||||
|
return resp.InternalServerError("copy file failed, " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
return resp.NoContent()
|
return resp.NoContent()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,7 +29,7 @@ func (e *Engine) Start() error {
|
|||||||
if err := meta.Initialize(utils.GetViper(), "redis."); err != nil {
|
if err := meta.Initialize(utils.GetViper(), "redis."); err != nil {
|
||||||
return fmt.Errorf("failed to initialize meta store: %v", err)
|
return fmt.Errorf("failed to initialize meta store: %v", err)
|
||||||
}
|
}
|
||||||
filesystem := NewFileSystemManager(meta, object)
|
filesystem := NewFileSystemManager(meta, object, utils.GetViper().GetString("robotfs.data_path"))
|
||||||
e.FileSystemManager = filesystem
|
e.FileSystemManager = filesystem
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -15,12 +15,14 @@ type FileSystemManager struct {
|
|||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
meta store.MetaStore
|
meta store.MetaStore
|
||||||
storage *StorageManager
|
storage *StorageManager
|
||||||
|
root string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFileSystemManager(meta store.MetaStore, storage *StorageManager) *FileSystemManager {
|
func NewFileSystemManager(meta store.MetaStore, storage *StorageManager, root string) *FileSystemManager {
|
||||||
return &FileSystemManager{
|
return &FileSystemManager{
|
||||||
meta: meta,
|
meta: meta,
|
||||||
storage: storage,
|
storage: storage,
|
||||||
|
root: root,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,12 +231,15 @@ func (f *FileSystemManager) RenameFile(ctx context.Context, srcPath, dstPath uti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
newS3Key := dstPath.ToS3Key()
|
if isDir {
|
||||||
if err := f.storage.CopyObject(srcEntry.S3Key, newS3Key); err != nil {
|
return fmt.Errorf("rename not file")
|
||||||
return fmt.Errorf("rename file failed: %v", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
newEntry := utils.NewFileEntry(dstPath, newS3Key, srcEntry.Size, srcEntry.ContentType, srcEntry.Etag, srcEntry.VersionID)
|
if err := utils.Move(f.root, string(srcPath), string(dstPath)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
newEntry := utils.NewFileEntry(dstPath, dstPath.ToS3Key(), srcEntry.Size, srcEntry.ContentType, srcEntry.Etag, srcEntry.VersionID)
|
||||||
|
|
||||||
if err := f.meta.InsertEntry(ctx, newEntry); err != nil {
|
if err := f.meta.InsertEntry(ctx, newEntry); err != nil {
|
||||||
return fmt.Errorf("insert new entry failed: %v", err)
|
return fmt.Errorf("insert new entry failed: %v", err)
|
||||||
@ -244,8 +249,44 @@ func (f *FileSystemManager) RenameFile(ctx context.Context, srcPath, dstPath uti
|
|||||||
return fmt.Errorf("delete source entry failed: %v", err)
|
return fmt.Errorf("delete source entry failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := f.storage.DeleteObject(srcEntry.S3Key); err != nil {
|
return nil
|
||||||
return fmt.Errorf("delete old file failed: %v", err)
|
}
|
||||||
|
|
||||||
|
func (f *FileSystemManager) CopyFile(ctx context.Context, srcPath, dstPath utils.FullPath, isDir bool) error {
|
||||||
|
f.Lock()
|
||||||
|
defer f.Unlock()
|
||||||
|
|
||||||
|
if string(srcPath) == "/" || string(dstPath) == "/" {
|
||||||
|
return fmt.Errorf("cannot copy root")
|
||||||
|
}
|
||||||
|
|
||||||
|
srcEntry, err := f.FindEntry(ctx, srcPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("find src file failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if dstEntry, _ := f.FindEntry(ctx, dstPath); dstEntry != nil {
|
||||||
|
return fmt.Errorf("dst file %s already exists", dstPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
parentDir, _ := dstPath.DirAndName()
|
||||||
|
if parentDir != "/" {
|
||||||
|
if parentEntry, _ := f.FindEntry(ctx, utils.FullPath(parentDir)); parentEntry == nil {
|
||||||
|
return fmt.Errorf("parent directory %s does not exist", parentDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if isDir {
|
||||||
|
return fmt.Errorf("copy not file")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := utils.Clone(f.root, string(srcPath), string(dstPath)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
newEntry := utils.NewFileEntry(dstPath, dstPath.ToS3Key(), srcEntry.Size, srcEntry.ContentType, srcEntry.Etag, srcEntry.VersionID)
|
||||||
|
if err := f.meta.InsertEntry(ctx, newEntry); err != nil {
|
||||||
|
return fmt.Errorf("insert new entry failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -55,7 +55,12 @@ func NewStorageManager(s3Config *S3Config) (*StorageManager, error) {
|
|||||||
|
|
||||||
s3Client := s3.New(awsSession)
|
s3Client := s3.New(awsSession)
|
||||||
|
|
||||||
uploader := s3manager.NewUploader(awsSession)
|
uploader := s3manager.NewUploader(awsSession, func(u *s3manager.Uploader) {
|
||||||
|
u.PartSize = 100 * 1024 * 1024
|
||||||
|
u.Concurrency = 5
|
||||||
|
u.LeavePartsOnError = false
|
||||||
|
u.BufferProvider = s3manager.NewBufferedReadSeekerWriteToPool(25 * 1024 * 1024)
|
||||||
|
})
|
||||||
downloader := s3manager.NewDownloader(awsSession)
|
downloader := s3manager.NewDownloader(awsSession)
|
||||||
|
|
||||||
return &StorageManager{
|
return &StorageManager{
|
||||||
@ -185,24 +190,3 @@ func (sm *StorageManager) CopyObject(oldS3key, newS3Key string) error {
|
|||||||
Key: aws.String(newS3Key),
|
Key: aws.String(newS3Key),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *StorageManager) ListObjects(prefix string) ([]string, error) {
|
|
||||||
var result []string
|
|
||||||
|
|
||||||
input := &s3.ListObjectsV2Input{
|
|
||||||
Bucket: aws.String(sm.bucketName),
|
|
||||||
Prefix: aws.String(prefix),
|
|
||||||
}
|
|
||||||
|
|
||||||
err := sm.s3Client.ListObjectsV2Pages(input, func(page *s3.ListObjectsV2Output, lastPage bool) bool {
|
|
||||||
for _, obj := range page.Contents {
|
|
||||||
result = append(result, *obj.Key)
|
|
||||||
}
|
|
||||||
return !lastPage
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|||||||
@ -5,8 +5,8 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CloneFile(src, dst string) error {
|
func Clone(root, src, dst string) error {
|
||||||
cmd := exec.Command("juicefs", "clone", src, dst)
|
cmd := exec.Command("juicefs", "clone", root+src, root+dst)
|
||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("clone failed: %v, output: %s", err, string(output))
|
return fmt.Errorf("clone failed: %v, output: %s", err, string(output))
|
||||||
@ -14,3 +14,12 @@ func CloneFile(src, dst string) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Move(root, src, dst string) error {
|
||||||
|
cmd := exec.Command("mv", root+src, root+dst)
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("move failed: %v, output: %s", err, string(output))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user