http: Update interfaces for List/ListR/Put/Update
This commit is contained in:
parent
83b642e98f
commit
afc8cc550a
1 changed files with 49 additions and 67 deletions
116
http/http.go
116
http/http.go
|
@ -16,15 +16,15 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"golang.org/x/net/html"
|
|
||||||
|
|
||||||
"github.com/ncw/rclone/fs"
|
"github.com/ncw/rclone/fs"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"golang.org/x/net/html"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var errorReadOnly = errors.New("http remotes are read only")
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
fsi := &fs.RegInfo{
|
fsi := &fs.RegInfo{
|
||||||
Name: "http",
|
Name: "http",
|
||||||
|
@ -32,10 +32,10 @@ func init() {
|
||||||
NewFs: NewFs,
|
NewFs: NewFs,
|
||||||
Options: []fs.Option{{
|
Options: []fs.Option{{
|
||||||
Name: "endpoint",
|
Name: "endpoint",
|
||||||
Help: "http host to connect to",
|
Help: "URL of http host to connect to",
|
||||||
Optional: false,
|
Optional: false,
|
||||||
Examples: []fs.OptionExample{{
|
Examples: []fs.OptionExample{{
|
||||||
Value: "example.com",
|
Value: "https://example.com",
|
||||||
Help: "Connect to example.com",
|
Help: "Connect to example.com",
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
|
@ -278,24 +278,34 @@ func (f *Fs) readDir(p string) ([]*entry, error) {
|
||||||
return entries, nil
|
return entries, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Fs) list(out fs.ListOpts, dir string, level int, wg *sync.WaitGroup, tokens chan struct{}) {
|
// List the objects and directories in dir into entries. The
|
||||||
defer wg.Done()
|
// entries can be returned in any order but should be for a
|
||||||
// take a token
|
// complete directory.
|
||||||
<-tokens
|
//
|
||||||
// return it when done
|
// dir should be "" to list the root, and should not have
|
||||||
defer func() {
|
// trailing slashes.
|
||||||
tokens <- struct{}{}
|
//
|
||||||
}()
|
// This should return ErrDirNotFound if the directory isn't
|
||||||
|
// found.
|
||||||
|
func (f *Fs) List(dir string) (entries fs.DirEntries, err error) {
|
||||||
|
endpoint := path.Join(f.root, dir)
|
||||||
|
if !strings.HasSuffix(dir, "/") {
|
||||||
|
endpoint += "/"
|
||||||
|
}
|
||||||
|
ok, err := f.dirExists(endpoint)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "List failed")
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return nil, fs.ErrorDirNotFound
|
||||||
|
}
|
||||||
httpDir := path.Join(f.root, dir)
|
httpDir := path.Join(f.root, dir)
|
||||||
if !strings.HasSuffix(dir, "/") {
|
if !strings.HasSuffix(dir, "/") {
|
||||||
httpDir += "/"
|
httpDir += "/"
|
||||||
}
|
}
|
||||||
infos, err := f.readDir(httpDir)
|
infos, err := f.readDir(httpDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrapf(err, "error listing %q", dir)
|
return nil, errors.Wrapf(err, "error listing %q", dir)
|
||||||
fs.Errorf(f, "Listing failed: %v", err)
|
|
||||||
out.SetError(err)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
for _, info := range infos {
|
for _, info := range infos {
|
||||||
remote := ""
|
remote := ""
|
||||||
|
@ -305,19 +315,13 @@ func (f *Fs) list(out fs.ListOpts, dir string, level int, wg *sync.WaitGroup, to
|
||||||
remote = info.Name()
|
remote = info.Name()
|
||||||
}
|
}
|
||||||
if info.IsDir() {
|
if info.IsDir() {
|
||||||
if out.IncludeDirectory(remote) {
|
dir := &fs.Dir{
|
||||||
dir := &fs.Dir{
|
Name: remote,
|
||||||
Name: remote,
|
When: info.ModTime(),
|
||||||
When: info.ModTime(),
|
Bytes: 0,
|
||||||
Bytes: 0,
|
Count: 0,
|
||||||
Count: 0,
|
|
||||||
}
|
|
||||||
out.AddDir(dir)
|
|
||||||
if level < out.Level() {
|
|
||||||
wg.Add(1)
|
|
||||||
go f.list(out, remote, level+1, wg, tokens)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
entries = append(entries, dir)
|
||||||
} else {
|
} else {
|
||||||
file := &Object{
|
file := &Object{
|
||||||
fs: f,
|
fs: f,
|
||||||
|
@ -327,41 +331,19 @@ func (f *Fs) list(out fs.ListOpts, dir string, level int, wg *sync.WaitGroup, to
|
||||||
if err = file.stat(); err != nil {
|
if err = file.stat(); err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
out.Add(file)
|
entries = append(entries, file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return entries, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// List the files and directories starting at <dir>
|
// Put in to the remote path with the modTime given of the given size
|
||||||
func (f *Fs) List(out fs.ListOpts, dir string) {
|
//
|
||||||
endpoint := path.Join(f.root, dir)
|
// May create the object even if it returns an error - if so
|
||||||
if !strings.HasSuffix(dir, "/") {
|
// will return the object and the error, otherwise will return
|
||||||
endpoint += "/"
|
// nil and the error
|
||||||
}
|
func (f *Fs) Put(in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs.Object, error) {
|
||||||
ok, err := f.dirExists(endpoint)
|
return nil, errorReadOnly
|
||||||
if err != nil {
|
|
||||||
out.SetError(errors.Wrap(err, "List failed"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
out.SetError(fs.ErrorDirNotFound)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// tokens to control the concurrency
|
|
||||||
tokens := make(chan struct{}, fs.Config.Checkers)
|
|
||||||
for i := 0; i < fs.Config.Checkers; i++ {
|
|
||||||
tokens <- struct{}{}
|
|
||||||
}
|
|
||||||
wg := new(sync.WaitGroup)
|
|
||||||
wg.Add(1)
|
|
||||||
f.list(out, dir, 1, wg, tokens)
|
|
||||||
wg.Wait()
|
|
||||||
out.Finished()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Put data from <in> into a new remote http file object described by <src.Remote()> and <src.ModTime()>
|
|
||||||
func (f *Fs) Put(in io.Reader, src fs.ObjectInfo) (fs.Object, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fs is the filesystem this remote http file object is located within
|
// Fs is the filesystem this remote http file object is located within
|
||||||
|
@ -442,7 +424,7 @@ func (o *Object) stat() error {
|
||||||
//
|
//
|
||||||
// it also updates the info field
|
// it also updates the info field
|
||||||
func (o *Object) SetModTime(modTime time.Time) error {
|
func (o *Object) SetModTime(modTime time.Time) error {
|
||||||
return nil
|
return errorReadOnly
|
||||||
}
|
}
|
||||||
|
|
||||||
// Storable returns whether the remote http file is a regular file (not a directory, symbolic link, block device, character device, named pipe, etc)
|
// Storable returns whether the remote http file is a regular file (not a directory, symbolic link, block device, character device, named pipe, etc)
|
||||||
|
@ -502,22 +484,22 @@ func (f *Fs) Hashes() fs.HashSet {
|
||||||
|
|
||||||
// Mkdir makes the root directory of the Fs object
|
// Mkdir makes the root directory of the Fs object
|
||||||
func (f *Fs) Mkdir(dir string) error {
|
func (f *Fs) Mkdir(dir string) error {
|
||||||
return nil
|
return errorReadOnly
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove a remote http file object
|
// Remove a remote http file object
|
||||||
func (o *Object) Remove() error {
|
func (o *Object) Remove() error {
|
||||||
return nil
|
return errorReadOnly
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rmdir removes the root directory of the Fs object
|
// Rmdir removes the root directory of the Fs object
|
||||||
func (f *Fs) Rmdir(dir string) error {
|
func (f *Fs) Rmdir(dir string) error {
|
||||||
return nil
|
return errorReadOnly
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update a remote http file using the data <in> and ModTime from <src>
|
// Update in to the object with the modTime given of the given size
|
||||||
func (o *Object) Update(in io.Reader, src fs.ObjectInfo) error {
|
func (o *Object) Update(in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) error {
|
||||||
return nil
|
return errorReadOnly
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the interfaces are satisfied
|
// Check the interfaces are satisfied
|
||||||
|
|
Loading…
Reference in a new issue