github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/backend/fichier/object.go (about)

     1  package fichier
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  	"net/http"
     9  	"time"
    10  
    11  	"github.com/rclone/rclone/fs"
    12  	"github.com/rclone/rclone/fs/hash"
    13  	"github.com/rclone/rclone/lib/rest"
    14  )
    15  
    16  // Object is a filesystem like object provided by an Fs
    17  type Object struct {
    18  	fs     *Fs
    19  	remote string
    20  	file   File
    21  }
    22  
    23  // String returns a description of the Object
    24  func (o *Object) String() string {
    25  	return o.file.Filename
    26  }
    27  
    28  // Remote returns the remote path
    29  func (o *Object) Remote() string {
    30  	return o.remote
    31  }
    32  
    33  // ModTime returns the modification date of the file
    34  // It should return a best guess if one isn't available
    35  func (o *Object) ModTime(ctx context.Context) time.Time {
    36  	modTime, err := time.Parse("2006-01-02 15:04:05", o.file.Date)
    37  
    38  	if err != nil {
    39  		return time.Now()
    40  	}
    41  
    42  	return modTime
    43  }
    44  
    45  // Size returns the size of the file
    46  func (o *Object) Size() int64 {
    47  	return o.file.Size
    48  }
    49  
    50  // Fs returns read only access to the Fs that this object is part of
    51  func (o *Object) Fs() fs.Info {
    52  	return o.fs
    53  }
    54  
    55  // Hash returns the selected checksum of the file
    56  // If no checksum is available it returns ""
    57  func (o *Object) Hash(ctx context.Context, t hash.Type) (string, error) {
    58  	if t != hash.Whirlpool {
    59  		return "", hash.ErrUnsupported
    60  	}
    61  
    62  	return o.file.Checksum, nil
    63  }
    64  
    65  // Storable says whether this object can be stored
    66  func (o *Object) Storable() bool {
    67  	return true
    68  }
    69  
    70  // SetModTime sets the metadata on the object to set the modification date
    71  func (o *Object) SetModTime(context.Context, time.Time) error {
    72  	return fs.ErrorCantSetModTime
    73  	//return errors.New("setting modtime is not supported for 1fichier remotes")
    74  }
    75  
    76  func (o *Object) setMetaData(file File) {
    77  	o.file = file
    78  }
    79  
    80  // Open opens the file for read.  Call Close() on the returned io.ReadCloser
    81  func (o *Object) Open(ctx context.Context, options ...fs.OpenOption) (io.ReadCloser, error) {
    82  	fs.FixRangeOption(options, o.file.Size)
    83  	downloadToken, err := o.fs.getDownloadToken(ctx, o.file.URL)
    84  
    85  	if err != nil {
    86  		return nil, err
    87  	}
    88  
    89  	var resp *http.Response
    90  	opts := rest.Opts{
    91  		Method:  "GET",
    92  		RootURL: downloadToken.URL,
    93  		Options: options,
    94  	}
    95  
    96  	err = o.fs.pacer.Call(func() (bool, error) {
    97  		resp, err = o.fs.rest.Call(ctx, &opts)
    98  		return shouldRetry(ctx, resp, err)
    99  	})
   100  
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  	return resp.Body, err
   105  }
   106  
   107  // Update in to the object with the modTime given of the given size
   108  //
   109  // When called from outside an Fs by rclone, src.Size() will always be >= 0.
   110  // But for unknown-sized objects (indicated by src.Size() == -1), Upload should either
   111  // return an error or update the object properly (rather than e.g. calling panic).
   112  func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) error {
   113  	if src.Size() < 0 {
   114  		return errors.New("refusing to update with unknown size")
   115  	}
   116  
   117  	// upload with new size but old name
   118  	info, err := o.fs.putUnchecked(ctx, in, o.Remote(), src.Size(), options...)
   119  	if err != nil {
   120  		return err
   121  	}
   122  
   123  	// Delete duplicate after successful upload
   124  	err = o.Remove(ctx)
   125  	if err != nil {
   126  		return fmt.Errorf("failed to remove old version: %w", err)
   127  	}
   128  
   129  	// Replace guts of old object with new one
   130  	*o = *info.(*Object)
   131  
   132  	return nil
   133  }
   134  
   135  // Remove removes this object
   136  func (o *Object) Remove(ctx context.Context) error {
   137  	// fs.Debugf(f, "Removing file `%s` with url `%s`", o.file.Filename, o.file.URL)
   138  
   139  	_, err := o.fs.deleteFile(ctx, o.file.URL)
   140  
   141  	if err != nil {
   142  		return err
   143  	}
   144  
   145  	return nil
   146  }
   147  
   148  // MimeType of an Object if known, "" otherwise
   149  func (o *Object) MimeType(ctx context.Context) string {
   150  	return o.file.ContentType
   151  }
   152  
   153  // ID returns the ID of the Object if known, or "" if not
   154  func (o *Object) ID() string {
   155  	return o.file.URL
   156  }
   157  
   158  // Check the interfaces are satisfied
   159  var (
   160  	_ fs.Object    = (*Object)(nil)
   161  	_ fs.MimeTyper = (*Object)(nil)
   162  	_ fs.IDer      = (*Object)(nil)
   163  )