forked from TrueCloudLab/rclone
ulozto: implement Mover and DirMover interfaces.
This commit is contained in:
parent
c9ce384ec7
commit
571d20d126
4 changed files with 112 additions and 3 deletions
|
@ -200,6 +200,26 @@ type UpdateDescriptionRequest struct {
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MoveFolderRequest represents the JSON API object that's
|
||||||
|
// sent to the folder moving API endpoint.
|
||||||
|
type MoveFolderRequest struct {
|
||||||
|
FolderSlugs []string `json:"slugs"`
|
||||||
|
NewParentFolderSlug string `json:"parent_folder_slug"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenameFolderRequest represents the JSON API object that's
|
||||||
|
// sent to the folder moving API endpoint.
|
||||||
|
type RenameFolderRequest struct {
|
||||||
|
NewName string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MoveFileRequest represents the JSON API object that's
|
||||||
|
// sent to the file moving API endpoint.
|
||||||
|
type MoveFileRequest struct {
|
||||||
|
ParentFolderSlug string `json:"folder_slug,omitempty"`
|
||||||
|
NewFilename string `json:"name,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// GetDownloadLinkRequest represents the JSON API object that's
|
// GetDownloadLinkRequest represents the JSON API object that's
|
||||||
// sent to the API endpoint that generates CDN download links for file payloads.
|
// sent to the API endpoint that generates CDN download links for file payloads.
|
||||||
type GetDownloadLinkRequest struct {
|
type GetDownloadLinkRequest struct {
|
||||||
|
|
|
@ -537,6 +537,92 @@ func (f *Fs) Rmdir(ctx context.Context, dir string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Move implements the optional method fs.Mover.Move.
|
||||||
|
func (f *Fs) Move(ctx context.Context, src fs.Object, remote string) (fs.Object, error) {
|
||||||
|
if remote == src.Remote() {
|
||||||
|
// Already there, do nothing
|
||||||
|
return src, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
srcObj, ok := src.(*Object)
|
||||||
|
if !ok {
|
||||||
|
fs.Debugf(src, "Can't move - not same remote type")
|
||||||
|
return nil, fs.ErrorCantMove
|
||||||
|
}
|
||||||
|
|
||||||
|
filename, folderSlug, err := f.dirCache.FindPath(ctx, remote, true)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
newObj := &Object{}
|
||||||
|
newObj.copyFrom(srcObj)
|
||||||
|
newObj.remote = remote
|
||||||
|
|
||||||
|
return newObj, newObj.updateFileProperties(ctx, api.MoveFileRequest{
|
||||||
|
ParentFolderSlug: folderSlug,
|
||||||
|
NewFilename: filename,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// DirMove implements the optional method fs.DirMover.DirMove.
|
||||||
|
func (f *Fs) DirMove(ctx context.Context, src fs.Fs, srcRemote, dstRemote string) error {
|
||||||
|
srcFs, ok := src.(*Fs)
|
||||||
|
if !ok {
|
||||||
|
fs.Debugf(srcFs, "Can't move directory - not same remote type")
|
||||||
|
return fs.ErrorCantDirMove
|
||||||
|
}
|
||||||
|
|
||||||
|
srcSlug, _, srcName, dstParentSlug, dstName, err := f.dirCache.DirMove(ctx, srcFs.dirCache, srcFs.root, srcRemote, f.root, dstRemote)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := rest.Opts{
|
||||||
|
Method: "PATCH",
|
||||||
|
Path: "/v6/user/" + f.opt.Username + "/folder-list/parent-folder",
|
||||||
|
}
|
||||||
|
|
||||||
|
req := api.MoveFolderRequest{
|
||||||
|
FolderSlugs: []string{srcSlug},
|
||||||
|
NewParentFolderSlug: dstParentSlug,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = f.pacer.Call(func() (bool, error) {
|
||||||
|
httpResp, err := f.rest.CallJSON(ctx, &opts, &req, nil)
|
||||||
|
return f.shouldRetry(ctx, httpResp, err, true)
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// The old folder doesn't exist anymore so clear the cache now instead of after renaming
|
||||||
|
srcFs.dirCache.FlushDir(srcRemote)
|
||||||
|
|
||||||
|
if srcName != dstName {
|
||||||
|
// There's no endpoint to rename the folder alongside moving it, so this has to happen separately.
|
||||||
|
opts = rest.Opts{
|
||||||
|
Method: "PATCH",
|
||||||
|
Path: "/v7/user/" + f.opt.Username + "/folder/" + srcSlug,
|
||||||
|
}
|
||||||
|
|
||||||
|
renameReq := api.RenameFolderRequest{
|
||||||
|
NewName: dstName,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = f.pacer.Call(func() (bool, error) {
|
||||||
|
httpResp, err := f.rest.CallJSON(ctx, &opts, &renameReq, nil)
|
||||||
|
return f.shouldRetry(ctx, httpResp, err, true)
|
||||||
|
})
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Name of the remote (as passed into NewFs)
|
// Name of the remote (as passed into NewFs)
|
||||||
func (f *Fs) Name() string {
|
func (f *Fs) Name() string {
|
||||||
return f.name
|
return f.name
|
||||||
|
@ -1179,6 +1265,8 @@ var (
|
||||||
_ dircache.DirCacher = (*Fs)(nil)
|
_ dircache.DirCacher = (*Fs)(nil)
|
||||||
_ fs.DirCacheFlusher = (*Fs)(nil)
|
_ fs.DirCacheFlusher = (*Fs)(nil)
|
||||||
_ fs.PutUncheckeder = (*Fs)(nil)
|
_ fs.PutUncheckeder = (*Fs)(nil)
|
||||||
|
_ fs.Mover = (*Fs)(nil)
|
||||||
|
_ fs.DirMover = (*Fs)(nil)
|
||||||
_ fs.Object = (*Object)(nil)
|
_ fs.Object = (*Object)(nil)
|
||||||
_ fs.ObjectInfo = (*RenamingObjectInfoProxy)(nil)
|
_ fs.ObjectInfo = (*RenamingObjectInfoProxy)(nil)
|
||||||
)
|
)
|
||||||
|
|
|
@ -527,7 +527,7 @@ upon backend-specific capabilities.
|
||||||
| SMB | No | No | Yes | Yes | No | No | Yes | Yes | No | No | Yes |
|
| SMB | No | No | Yes | Yes | No | No | Yes | Yes | No | No | Yes |
|
||||||
| SugarSync | Yes | Yes | Yes | Yes | No | No | Yes | No | Yes | No | Yes |
|
| SugarSync | Yes | Yes | Yes | Yes | No | No | Yes | No | Yes | No | Yes |
|
||||||
| Storj | Yes ² | Yes | Yes | No | No | Yes | Yes | No | Yes | No | No |
|
| Storj | Yes ² | Yes | Yes | No | No | Yes | Yes | No | Yes | No | No |
|
||||||
| Uloz.to | No | No | No | No | No | No | No | No | No | No | Yes |
|
| Uloz.to | No | No | Yes | Yes | No | No | No | No | No | No | Yes |
|
||||||
| Uptobox | No | Yes | Yes | Yes | No | No | No | No | No | No | No |
|
| Uptobox | No | Yes | Yes | Yes | No | No | No | No | No | No | No |
|
||||||
| WebDAV | Yes | Yes | Yes | Yes | No | No | Yes ³ | No | No | Yes | Yes |
|
| WebDAV | Yes | Yes | Yes | Yes | No | No | Yes ³ | No | No | Yes | Yes |
|
||||||
| Yandex Disk | Yes | Yes | Yes | Yes | Yes | No | Yes | No | Yes | Yes | Yes |
|
| Yandex Disk | Yes | Yes | Yes | Yes | Yes | No | Yes | No | Yes | Yes | Yes |
|
||||||
|
|
|
@ -94,7 +94,8 @@ precision.
|
||||||
|
|
||||||
A server calculated MD5 hash of the file is verified upon upload.
|
A server calculated MD5 hash of the file is verified upon upload.
|
||||||
Afterwards, the backend only serves the client-side calculated
|
Afterwards, the backend only serves the client-side calculated
|
||||||
hashes.
|
hashes. Hashes can also be retrieved upon creating a file download
|
||||||
|
link, but it's impractical for `list`-like use cases.
|
||||||
|
|
||||||
### Restricted filename characters
|
### Restricted filename characters
|
||||||
|
|
||||||
|
@ -111,7 +112,7 @@ as they can't be used in JSON strings.
|
||||||
### Transfers
|
### Transfers
|
||||||
|
|
||||||
All files are currently uploaded using a single HTTP request, so
|
All files are currently uploaded using a single HTTP request, so
|
||||||
for uploading large files a stable connection is necesary. Rclone will
|
for uploading large files a stable connection is necessary. Rclone will
|
||||||
upload up to `--transfers` chunks at the same time (shared among all
|
upload up to `--transfers` chunks at the same time (shared among all
|
||||||
uploads).
|
uploads).
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue