2019-06-27 02:39:01 +08:00
|
|
|
package fichier
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"io"
|
|
|
|
"net/http"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/pkg/errors"
|
2019-07-29 01:47:38 +08:00
|
|
|
"github.com/rclone/rclone/fs"
|
|
|
|
"github.com/rclone/rclone/fs/hash"
|
|
|
|
"github.com/rclone/rclone/lib/rest"
|
2019-06-27 02:39:01 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
// Object is a filesystem like object provided by an Fs
|
|
|
|
type Object struct {
|
|
|
|
fs *Fs
|
|
|
|
remote string
|
|
|
|
file File
|
|
|
|
}
|
|
|
|
|
|
|
|
// String returns a description of the Object
|
|
|
|
func (o *Object) String() string {
|
|
|
|
return o.file.Filename
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remote returns the remote path
|
|
|
|
func (o *Object) Remote() string {
|
|
|
|
return o.remote
|
|
|
|
}
|
|
|
|
|
|
|
|
// ModTime returns the modification date of the file
|
|
|
|
// It should return a best guess if one isn't available
|
|
|
|
func (o *Object) ModTime(ctx context.Context) time.Time {
|
|
|
|
modTime, err := time.Parse("2006-01-02 15:04:05", o.file.Date)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return time.Now()
|
|
|
|
}
|
|
|
|
|
|
|
|
return modTime
|
|
|
|
}
|
|
|
|
|
|
|
|
// Size returns the size of the file
|
|
|
|
func (o *Object) Size() int64 {
|
2019-10-01 19:34:38 +08:00
|
|
|
return o.file.Size
|
2019-06-27 02:39:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fs returns read only access to the Fs that this object is part of
|
|
|
|
func (o *Object) Fs() fs.Info {
|
|
|
|
return o.fs
|
|
|
|
}
|
|
|
|
|
|
|
|
// Hash returns the selected checksum of the file
|
|
|
|
// If no checksum is available it returns ""
|
|
|
|
func (o *Object) Hash(ctx context.Context, t hash.Type) (string, error) {
|
|
|
|
if t != hash.Whirlpool {
|
|
|
|
return "", hash.ErrUnsupported
|
|
|
|
}
|
|
|
|
|
|
|
|
return o.file.Checksum, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Storable says whether this object can be stored
|
|
|
|
func (o *Object) Storable() bool {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetModTime sets the metadata on the object to set the modification date
|
|
|
|
func (o *Object) SetModTime(context.Context, time.Time) error {
|
|
|
|
return fs.ErrorCantSetModTime
|
|
|
|
//return errors.New("setting modtime is not supported for 1fichier remotes")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Open opens the file for read. Call Close() on the returned io.ReadCloser
|
|
|
|
func (o *Object) Open(ctx context.Context, options ...fs.OpenOption) (io.ReadCloser, error) {
|
2019-10-01 19:34:38 +08:00
|
|
|
fs.FixRangeOption(options, o.file.Size)
|
2019-09-05 03:00:37 +08:00
|
|
|
downloadToken, err := o.fs.getDownloadToken(ctx, o.file.URL)
|
2019-06-27 02:39:01 +08:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var resp *http.Response
|
|
|
|
opts := rest.Opts{
|
|
|
|
Method: "GET",
|
|
|
|
RootURL: downloadToken.URL,
|
|
|
|
Options: options,
|
|
|
|
}
|
|
|
|
|
|
|
|
err = o.fs.pacer.Call(func() (bool, error) {
|
2019-09-05 03:00:37 +08:00
|
|
|
resp, err = o.fs.rest.Call(ctx, &opts)
|
2019-06-27 02:39:01 +08:00
|
|
|
return shouldRetry(resp, err)
|
|
|
|
})
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return resp.Body, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update in to the object with the modTime given of the given size
|
|
|
|
//
|
2020-05-25 14:05:53 +08:00
|
|
|
// When called from outside an Fs by rclone, src.Size() will always be >= 0.
|
2019-06-27 02:39:01 +08:00
|
|
|
// But for unknown-sized objects (indicated by src.Size() == -1), Upload should either
|
|
|
|
// return an error or update the object properly (rather than e.g. calling panic).
|
|
|
|
func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) error {
|
|
|
|
if src.Size() < 0 {
|
|
|
|
return errors.New("refusing to update with unknown size")
|
|
|
|
}
|
|
|
|
|
|
|
|
// upload with new size but old name
|
|
|
|
info, err := o.fs.putUnchecked(ctx, in, o.Remote(), src.Size(), options...)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete duplicate after successful upload
|
|
|
|
err = o.Remove(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "failed to remove old version")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Replace guts of old object with new one
|
|
|
|
*o = *info.(*Object)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove removes this object
|
|
|
|
func (o *Object) Remove(ctx context.Context) error {
|
|
|
|
// fs.Debugf(f, "Removing file `%s` with url `%s`", o.file.Filename, o.file.URL)
|
|
|
|
|
2019-09-05 03:00:37 +08:00
|
|
|
_, err := o.fs.deleteFile(ctx, o.file.URL)
|
2019-06-27 02:39:01 +08:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// MimeType of an Object if known, "" otherwise
|
|
|
|
func (o *Object) MimeType(ctx context.Context) string {
|
|
|
|
return o.file.ContentType
|
|
|
|
}
|
|
|
|
|
|
|
|
// ID returns the ID of the Object if known, or "" if not
|
|
|
|
func (o *Object) ID() string {
|
|
|
|
return o.file.URL
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check the interfaces are satisfied
|
|
|
|
var (
|
|
|
|
_ fs.Object = (*Object)(nil)
|
|
|
|
_ fs.MimeTyper = (*Object)(nil)
|
|
|
|
_ fs.IDer = (*Object)(nil)
|
|
|
|
)
|