github.com/10XDev/rclone@v1.52.3-0.20200626220027-16af9ab76b2a/backend/seafile/object.go (about) 1 package seafile 2 3 import ( 4 "context" 5 "io" 6 "time" 7 8 "github.com/rclone/rclone/fs" 9 "github.com/rclone/rclone/fs/hash" 10 ) 11 12 // Object describes a seafile object (also commonly called a file) 13 type Object struct { 14 fs *Fs // what this object is part of 15 id string // internal ID of object 16 remote string // The remote path (full path containing library name if target at root) 17 pathInLibrary string // Path of the object without the library name 18 size int64 // size of the object 19 modTime time.Time // modification time of the object 20 libraryID string // Needed to download the file 21 } 22 23 // ==================== Interface fs.DirEntry ==================== 24 25 // Return a string version 26 func (o *Object) String() string { 27 if o == nil { 28 return "<nil>" 29 } 30 return o.remote 31 } 32 33 // Remote returns the remote string 34 func (o *Object) Remote() string { 35 return o.remote 36 } 37 38 // ModTime returns last modified time 39 func (o *Object) ModTime(context.Context) time.Time { 40 return o.modTime 41 } 42 43 // Size returns the size of an object in bytes 44 func (o *Object) Size() int64 { 45 return o.size 46 } 47 48 // ==================== Interface fs.ObjectInfo ==================== 49 50 // Fs returns the parent Fs 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, ty hash.Type) (string, error) { 58 return "", hash.ErrUnsupported 59 } 60 61 // Storable says whether this object can be stored 62 func (o *Object) Storable() bool { 63 return true 64 } 65 66 // ==================== Interface fs.Object ==================== 67 68 // SetModTime sets the metadata on the object to set the modification date 69 func (o *Object) SetModTime(ctx context.Context, t time.Time) error { 70 return fs.ErrorCantSetModTime 71 } 72 73 // Open opens the file for read. Call Close() on the returned io.ReadCloser 74 func (o *Object) Open(ctx context.Context, options ...fs.OpenOption) (io.ReadCloser, error) { 75 downloadLink, err := o.fs.getDownloadLink(ctx, o.libraryID, o.pathInLibrary) 76 if err != nil { 77 return nil, err 78 } 79 reader, err := o.fs.download(ctx, downloadLink, o.Size(), options...) 80 if err != nil { 81 return nil, err 82 } 83 return reader, nil 84 } 85 86 // Update in to the object with the modTime given of the given size 87 // 88 // When called from outside an Fs by rclone, src.Size() will always be >= 0. 89 // But for unknown-sized objects (indicated by src.Size() == -1), Upload should either 90 // return an error or update the object properly (rather than e.g. calling panic). 91 func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) error { 92 // The upload sometimes return a temporary 500 error 93 // We cannot use the pacer to retry uploading the file as the upload link is single use only 94 for retry := 0; retry <= 3; retry++ { 95 uploadLink, err := o.fs.getUploadLink(ctx, o.libraryID) 96 if err != nil { 97 return err 98 } 99 100 uploaded, err := o.fs.upload(ctx, in, uploadLink, o.pathInLibrary) 101 if err == ErrorInternalDuringUpload { 102 // This is a temporary error, try again with a new upload link 103 continue 104 } 105 if err != nil { 106 return err 107 } 108 // Set the properties from the upload back to the object 109 o.size = uploaded.Size 110 o.id = uploaded.ID 111 112 return nil 113 } 114 return ErrorInternalDuringUpload 115 } 116 117 // Remove this object 118 func (o *Object) Remove(ctx context.Context) error { 119 return o.fs.deleteFile(ctx, o.libraryID, o.pathInLibrary) 120 } 121 122 // ==================== Optional Interface fs.IDer ==================== 123 124 // ID returns the ID of the Object if known, or "" if not 125 func (o *Object) ID() string { 126 return o.id 127 }